feat: support assigning child to existing device

This commit is contained in:
stu2not
2026-06-02 14:40:30 +08:00
parent cd32d4e64c
commit 57bafb003d
3 changed files with 137 additions and 19 deletions

View File

@@ -68,6 +68,41 @@
position: relative;
}
.pending-device-card {
margin: 0 48px 48px;
background: #FFFFFF;
border-radius: 24px;
padding: 48px 40px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
}
.pending-device-title {
font-size: 34px;
font-weight: 700;
color: #1A1A1A;
margin-bottom: 14px;
}
.pending-device-id {
max-width: 100%;
font-size: 28px;
color: #FF8C42;
font-weight: 600;
word-break: break-all;
text-align: center;
margin-bottom: 12px;
}
.pending-device-desc {
font-size: 26px;
color: #666666;
text-align: center;
line-height: 1.5;
}
.scan-frame {
background: #FFFFFF;
border-radius: 24px;

View File

@@ -350,26 +350,37 @@ export default function Bind() {
<Text className='title'>{isPendingBinding ? '补全绑定' : '扫码贴卡绑定设备'}</Text>
</View>
<View className='scan-area'>
<View className='scan-frame' onClick={handleScanCode}>
{isPendingBinding ? (
<View className='pending-device-card'>
<View className='icon-bg orange'>
<Image className='control-icon-img' src={require('../../assets/tab-icons/rings.png')} mode='aspectFit' />
</View>
<Text className='scan-text'>
{!canEditDeviceFields ? '请先完成儿童资料' : isScanning ? '正在扫码...' : '点击扫码'}
</Text>
<Text className='scan-hint'>
{!canEditDeviceFields ? '先选儿童,再扫设备二维码' : '扫描设备二维码或条码'}
</Text>
<Text className='pending-device-title'></Text>
<Text className='pending-device-id'>{pendingDeviceId}</Text>
<Text className='pending-device-desc'></Text>
</View>
) : (
<View className='scan-area'>
<View className='scan-frame' onClick={handleScanCode}>
<View className='icon-bg orange'>
<Image className='control-icon-img' src={require('../../assets/tab-icons/rings.png')} mode='aspectFit' />
</View>
<Text className='scan-text'>
{!canEditDeviceFields ? '请先完成儿童资料' : isScanning ? '正在扫码...' : '点击扫码'}
</Text>
<Text className='scan-hint'>
{!canEditDeviceFields ? '先选儿童,再扫设备二维码' : '扫描设备二维码或条码'}
</Text>
</View>
<View className='scan-corners'>
<View className='corner top-left'></View>
<View className='corner top-right'></View>
<View className='corner bottom-left'></View>
<View className='corner bottom-right'></View>
<View className='scan-corners'>
<View className='corner top-left'></View>
<View className='corner top-right'></View>
<View className='corner bottom-left'></View>
<View className='corner bottom-right'></View>
</View>
</View>
</View>
)}
<View className='bind-form'>
<View className='form-card'>
@@ -413,12 +424,17 @@ export default function Bind() {
</View>
<Text className='field-hint'>
{children.length > 0
? '可以选已有儿童,也可以在这里新建一个儿童后再绑定设备'
: '当前还没有儿童资料,请先创建一个儿童资料'}
{isPendingBinding
? children.length > 0
? '可以选已有儿童,也可以新建一个儿童后关联当前设备'
: '当前还没有儿童资料,请先创建一个儿童资料后关联设备'
: children.length > 0
? '可以选已有儿童,也可以在这里新建一个儿童后再绑定设备'
: '当前还没有儿童资料,请先创建一个儿童资料'}
</Text>
</View>
{!isPendingBinding && (
<View className='form-card'>
<Text className='form-title'></Text>
@@ -457,6 +473,7 @@ export default function Bind() {
</View>
)}
</View>
)}
<Button
className='submit-btn'
@@ -476,11 +493,11 @@ export default function Bind() {
</View>
<View className='tip-item'>
<Text className='tip-number'>2</Text>
<Text className='tip-text'></Text>
<Text className='tip-text'>{isPendingBinding ? '确认当前待关联设备,再选择要关联的孩子' : '扫描设备二维码,确认设备号和序列号正确'}</Text>
</View>
<View className='tip-item'>
<Text className='tip-number'>3</Text>
<Text className='tip-text'></Text>
<Text className='tip-text'>{isPendingBinding ? '点击完成儿童关联,设备会出现在该孩子下面' : '点击发送绑卡指令,然后去设备上贴自己的卡完成确认'}</Text>
</View>
</View>
{systemBanner}

View File

@@ -68,6 +68,7 @@ export default function Sleep() {
const [showDeleteChildModal, setShowDeleteChildModal] = useState(false)
const [showRoleModal, setShowRoleModal] = useState(false)
const [showFamilyModal, setShowFamilyModal] = useState(false)
const [showAssignDeviceModal, setShowAssignDeviceModal] = useState(false)
const [modalType, setModalType] = useState<'add' | 'edit'>('add')
const [childName, setChildName] = useState('')
const [editingChildId, setEditingChildId] = useState<number | null>(null)
@@ -334,9 +335,17 @@ export default function Sleep() {
const handleOpenAddChildFromSwitch = () => {
setShowChildModal(false)
setShowAssignDeviceModal(false)
handleOpenModal('add')
}
const handleAssignExistingDevice = (targetBinding: BindingListItem) => {
if (!targetBinding?.device_id) return
setSelectedBindingDeviceId(targetBinding.device_id)
setShowAssignDeviceModal(false)
Taro.navigateTo({ url: '/pages/bind/index' })
}
const handleSubmitModal = async () => {
const normalizedName = childName.trim()
if (!normalizedName) {
@@ -544,6 +553,11 @@ export default function Sleep() {
return
}
if (item.name === '关联现有设备') {
setShowAssignDeviceModal(true)
return
}
if (item.name === '绑定设备') {
if (!currentChild) {
handleOpenModal('add')
@@ -584,6 +598,7 @@ export default function Sleep() {
}
const parentDisplayName = parentInfo.nickname?.trim() || '家长'
const unassignedBindings = bindings.filter((item) => item.device_id && item.child_id === null)
const currentFirmwareLabel = firmwareStatus?.current_version || '--'
const latestFirmwareLabel = firmwareStatus?.latest_version || '--'
const currentUserId = getCurrentUserId()
@@ -637,6 +652,15 @@ export default function Sleep() {
arrow: true,
disabled: children.length === 0,
},
...(unassignedBindings.length > 0
? [{
icon: require('../../assets/tab-icons/rings.png'),
iconBgClass: 'green',
name: '关联现有设备',
value: `${unassignedBindings.length} 台待关联`,
arrow: true,
}]
: []),
{
icon: require('../../assets/tab-icons/rings.png'),
iconBgClass: 'green',
@@ -856,6 +880,48 @@ export default function Sleep() {
</View>
)}
{showAssignDeviceModal && (
<View className='modal-mask' onClick={() => setShowAssignDeviceModal(false)}>
<View
className='modal-card device-switch-card'
onClick={(event) => {
event.stopPropagation()
}}
>
<Text className='modal-title'></Text>
{unassignedBindings.length === 0 ? (
<Text className='device-switch-empty'></Text>
) : (
<View className='device-switch-list'>
{unassignedBindings.map((item) => (
<View
key={item.device_id}
className='device-switch-item'
onClick={() => handleAssignExistingDevice(item)}
>
<View className='device-switch-head'>
<Text className='device-switch-id'>{item.device_id}</Text>
<Text className='device-switch-tag'></Text>
</View>
<Text className='device-switch-name'></Text>
</View>
))}
</View>
)}
<View className='device-switch-footer'>
<Text className='device-switch-add' onClick={handleOpenAddChildFromSwitch}>
+
</Text>
</View>
<View className='modal-actions'>
<Text className='modal-action cancel' onClick={() => setShowAssignDeviceModal(false)}>
</Text>
</View>
</View>
</View>
)}
{showModal && (
<View className='modal-mask'>
<View className='modal-card'>