Refine device-first baby management

This commit is contained in:
stu2not
2026-07-02 11:43:09 +08:00
parent 998401f8c9
commit b4fef6d2e0
11 changed files with 275 additions and 201 deletions
+148 -128
View File
@@ -90,11 +90,11 @@ export default function Sleep() {
const [familyInviteExpiresAt, setFamilyInviteExpiresAt] = useState('')
const [showModal, setShowModal] = useState(false)
const [showChildModal, setShowChildModal] = useState(false)
const [showDeleteChildModal, setShowDeleteChildModal] = useState(false)
const [showRoleModal, setShowRoleModal] = useState(false)
const [showFamilyModal, setShowFamilyModal] = useState(false)
const [showFamilyNameModal, setShowFamilyNameModal] = useState(false)
const [showAssignDeviceModal, setShowAssignDeviceModal] = useState(false)
const [showCardsModal, setShowCardsModal] = useState(false)
const [showCardNameModal, setShowCardNameModal] = useState(false)
const [childName, setChildName] = useState('')
const [editingChildId, setEditingChildId] = useState<number | null>(null)
@@ -126,7 +126,7 @@ export default function Sleep() {
}, [])
useShareAppMessage(() => {
const targetName = currentChild?.child_name || binding?.device_id || '孩子'
const targetName = currentChild?.child_name || binding?.device_id || '宝贝'
return {
title: `邀请你加入${targetName}的家庭共享`,
path: familyInvitePath || '/pages/device/index',
@@ -567,7 +567,7 @@ export default function Sleep() {
void loadCurrentDeviceCards(nextBinding?.device_id)
setShowChildModal(false)
Taro.showToast({
title: '已切换当前孩子',
title: '已切换当前宝贝',
icon: 'success',
})
}
@@ -621,16 +621,50 @@ export default function Sleep() {
Taro.navigateTo({ url: '/pages/bind/index?mode=assign' })
}
const handleDeleteUnassignedDevice = (targetBinding: BindingListItem) => {
if (!targetBinding?.device_id) return
Taro.showModal({
title: '删除设备',
content: `确定要从当前账号删除设备 ${targetBinding.device_id} 吗?删除后需要重新扫码绑定。`,
confirmText: '删除',
confirmColor: '#E5484D',
success: async (result) => {
if (!result.confirm) return
try {
await unbindDevice(targetBinding.device_id)
if (binding?.device_id === targetBinding.device_id) {
clearSelectedBindingDeviceId()
}
Taro.showToast({ title: '已删除设备', icon: 'success' })
await loadData()
} catch (error: any) {
Taro.showToast({
title: error?.message || '删除设备失败,请重试',
icon: 'none',
})
}
},
})
}
const handleOpenAddCard = () => {
if (!binding?.device_id) return
setShowCardsModal(false)
Taro.navigateTo({ url: `/pages/bind/index?mode=card&device_id=${encodeURIComponent(binding.device_id)}` })
}
const handleSubmitModal = async () => {
const normalizedName = childName.trim()
if (!normalizedName) {
Taro.showToast({ title: '请输入儿童昵称', icon: 'none' })
Taro.showToast({ title: '请输入宝贝昵称', icon: 'none' })
return
}
try {
if (!editingChildId) {
Taro.showToast({ title: '当前没有可修改的孩子', icon: 'none' })
Taro.showToast({ title: '当前没有可修改的宝贝', icon: 'none' })
return
}
@@ -651,11 +685,11 @@ export default function Sleep() {
const childBinding = bindings.find((item) => item.child_id === child.child_id) || null
const isCurrentChild = currentChild?.child_id === child.child_id
const content = childBinding?.device_id
? '删除后,' + child.child_name + ' 将不再显示,设备 ' + childBinding.device_id + ' 会保留但不再分配给该孩子。确定删除吗?'
? '删除后,' + child.child_name + ' 将不再显示,设备 ' + childBinding.device_id + ' 会保留但不再分配给该宝贝。确定删除吗?'
: '删除后,' + child.child_name + ' 将不再显示。确定删除吗?'
Taro.showModal({
title: '删除孩子',
title: '删除宝贝',
content,
confirmText: '删除',
confirmColor: '#E5484D',
@@ -670,7 +704,7 @@ export default function Sleep() {
if (isCurrentChild && childBinding?.device_id && binding?.device_id === childBinding.device_id) {
clearSelectedBindingDeviceId()
}
setShowDeleteChildModal(false)
setShowChildModal(false)
Taro.showToast({ title: '已删除', icon: 'success' })
await loadData()
} catch (error: any) {
@@ -885,16 +919,11 @@ export default function Sleep() {
const handleMenuClick = (item: MenuItem) => {
if (item.disabled) return
if (item.name === '当前孩子') {
if (item.name === '当前宝贝') {
setShowChildModal(true)
return
}
if (item.name === '删除孩子') {
setShowDeleteChildModal(true)
return
}
if (item.name === '关联现有设备') {
setShowAssignDeviceModal(true)
return
@@ -905,9 +934,8 @@ export default function Sleep() {
return
}
if (item.name === '添加设备卡') {
if (!binding?.device_id) return
Taro.navigateTo({ url: `/pages/bind/index?mode=card&device_id=${encodeURIComponent(binding.device_id)}` })
if (item.name === '我的卡片') {
setShowCardsModal(true)
return
}
@@ -951,8 +979,8 @@ export default function Sleep() {
<View className='guest-manage-card'>
<Text className='guest-manage-icon'>⚙️</Text>
<Text className='guest-manage-title'>管理孩子资料和设备</Text>
<Text className='guest-manage-desc'>登录后可创建孩子资料、绑定伴伴设备、管理卡片、设置休眠时间和家庭成员。</Text>
<Text className='guest-manage-title'>管理宝贝资料和设备</Text>
<Text className='guest-manage-desc'>登录后可创建宝贝资料、绑定伴伴设备、管理卡片、设置休眠时间和家庭成员。</Text>
<View
className='guest-manage-btn'
onClick={() => {
@@ -966,8 +994,8 @@ export default function Sleep() {
<View className='guest-manage-list'>
<View className='guest-manage-item'>
<Text className='guest-manage-item-title'>孩子资料</Text>
<Text className='guest-manage-item-desc'>为不同孩子维护独立设备和会话。</Text>
<Text className='guest-manage-item-title'>宝贝资料</Text>
<Text className='guest-manage-item-desc'>为不同宝贝维护独立设备和会话。</Text>
</View>
<View className='guest-manage-item'>
<Text className='guest-manage-item-title'>设备绑定</Text>
@@ -1044,22 +1072,19 @@ export default function Sleep() {
: firmwareStatus?.update_available
? '发现可更新版本'
: '当前设备版本状态'
const cardValue = !binding?.device_id
? '未绑定'
: isLoadingCards
? '查询中'
: `${currentCardGroup?.card_count || 0} 张`
const menuItems: MenuItem[] = [
{
icon: require('../../assets/tab-icons/orange-robot.png'),
iconBgClass: 'orange',
name: '当前孩子',
name: '当前宝贝',
value: currentChildName,
arrow: true,
},
{
icon: require('../../assets/tab-icons/broken-rings.png'),
iconBgClass: 'red',
name: '删除孩子',
value: children.length > 0 ? `${children.length} 个可选` : '未添加',
arrow: true,
disabled: children.length === 0,
},
...(unassignedBindings.length > 0
? [{
icon: require('../../assets/tab-icons/rings.png'),
@@ -1079,8 +1104,8 @@ export default function Sleep() {
{
icon: require('../../assets/tab-icons/rings.png'),
iconBgClass: 'green',
name: '添加设备卡',
value: binding?.device_id ? '给当前设备加卡' : '未绑定',
name: '我的卡片',
value: cardValue,
arrow: true,
disabled: !binding,
},
@@ -1155,11 +1180,11 @@ export default function Sleep() {
<View className='summary-card'>
<View className='summary-row'>
<Text className='summary-label'>儿童资料数</Text>
<Text className='summary-label'>宝贝资料数</Text>
<Text className='summary-value'>{children.length} 个</Text>
</View>
<View className='summary-row'>
<Text className='summary-label'>当前儿童</Text>
<Text className='summary-label'>当前宝贝</Text>
<Text className='summary-value'>{currentChildName}</Text>
</View>
<View className='summary-row'>
@@ -1197,50 +1222,6 @@ export default function Sleep() {
</View>
</View>
<View className={`bound-cards-card ${binding?.device_id ? '' : 'disabled'}`}>
<View className='bound-cards-header'>
<View className='bound-cards-heading'>
<Text className='bound-cards-title'>已绑卡片</Text>
<Text className='bound-cards-subtitle'>{binding?.device_id || '当前未绑定设备'}</Text>
</View>
<Text className='bound-cards-count'>
{isLoadingCards ? '查询中' : `${currentCardGroup?.card_count || 0} 张`}
</Text>
</View>
{!binding?.device_id ? (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>绑定设备后可查看卡片 UUID</Text>
</View>
) : isLoadingCards ? (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>卡片加载中...</Text>
</View>
) : currentCardGroup?.cards.length ? (
<View className='bound-card-list'>
{currentCardGroup.cards.map((card) => (
<View className='bound-card-item' key={`${currentCardGroup.device_id}-${card.card_id}`}>
<View className='bound-card-main'>
<Text className={`bound-card-name ${card.card_name ? '' : 'empty'}`}>
{card.card_name || '未命名卡片'}
</Text>
<Text className='bound-card-uuid'>{card.card_uuid}</Text>
</View>
{canEditCardName && (
<Text className='bound-card-edit' onClick={() => handleOpenCardNameModal(card)}>
编辑
</Text>
)}
</View>
))}
</View>
) : (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>当前设备暂无已绑卡片</Text>
</View>
)}
</View>
<View className='menu-card'>
{menuItems.map((item, index) => (
<View key={index}>
@@ -1279,9 +1260,9 @@ export default function Sleep() {
event.stopPropagation()
}}
>
<Text className='modal-title'>切换当前孩子</Text>
<Text className='modal-title'>切换当前宝贝</Text>
{children.length === 0 ? (
<Text className='device-switch-empty'>当前还没有儿童资料</Text>
<Text className='device-switch-empty'>当前还没有宝贝资料</Text>
) : (
<View className='device-switch-list'>
{children.map((item) => {
@@ -1308,6 +1289,15 @@ export default function Sleep() {
修改
</Text>
)}
<Text
className='device-switch-delete'
onClick={(event) => {
event.stopPropagation()
handleDeleteChild(item)
}}
>
删除
</Text>
</View>
</View>
<Text className='device-switch-name'>{itemBinding?.device_id || '未绑定设备'}</Text>
@@ -1325,50 +1315,6 @@ export default function Sleep() {
</View>
)}
{showDeleteChildModal && (
<View className='modal-mask' onClick={() => setShowDeleteChildModal(false)}>
<View
className='modal-card device-switch-card'
onClick={(event) => {
event.stopPropagation()
}}
>
<Text className='modal-title'>选择要删除的孩子</Text>
{children.length === 0 ? (
<Text className='device-switch-empty'>当前还没有儿童资料</Text>
) : (
<View className='device-switch-list'>
{children.map((item) => {
const isActive = currentChild?.child_id === item.child_id
const itemBinding = bindings.find((bindingItem) => bindingItem.child_id === item.child_id) || null
return (
<View
key={item.child_id}
className='device-switch-item delete-child-item'
onClick={() => handleDeleteChild(item)}
>
<View className='device-switch-head'>
<Text className='device-switch-id'>{item.child_name}</Text>
<View className='device-switch-tags'>
{isActive && <Text className='device-switch-tag'>当前</Text>}
<Text className='device-switch-tag danger'>删除</Text>
</View>
</View>
<Text className='device-switch-name'>{itemBinding?.device_id || '未绑定设备'}</Text>
</View>
)
})}
</View>
)}
<View className='modal-actions'>
<Text className='modal-action cancel' onClick={() => setShowDeleteChildModal(false)}>
关闭
</Text>
</View>
</View>
</View>
)}
{showAssignDeviceModal && (
<View className='modal-mask' onClick={() => setShowAssignDeviceModal(false)}>
<View
@@ -1390,9 +1336,20 @@ export default function Sleep() {
>
<View className='device-switch-head'>
<Text className='device-switch-id'>{item.device_id}</Text>
<Text className='device-switch-tag'>待关联</Text>
<View className='device-switch-tags'>
<Text className='device-switch-tag'>待关联</Text>
<Text
className='device-switch-delete'
onClick={(event) => {
event.stopPropagation()
handleDeleteUnassignedDevice(item)
}}
>
删除
</Text>
</View>
</View>
<Text className='device-switch-name'>未关联孩子</Text>
<Text className='device-switch-name'>未关联宝贝</Text>
</View>
))}
</View>
@@ -1406,15 +1363,78 @@ export default function Sleep() {
</View>
)}
{showCardsModal && (
<View className='modal-mask' onClick={() => setShowCardsModal(false)}>
<View
className='modal-card cards-modal-card'
onClick={(event) => {
event.stopPropagation()
}}
>
<Text className='modal-title'>我的卡片</Text>
<View className='cards-modal-summary'>
<Text className='cards-modal-device'>{binding?.device_id || '当前未绑定设备'}</Text>
<Text className='bound-cards-count'>
{isLoadingCards ? '查询中' : `${currentCardGroup?.card_count || 0} 张`}
</Text>
</View>
{!binding?.device_id ? (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>绑定设备后可查看卡片 UUID</Text>
</View>
) : isLoadingCards ? (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>卡片加载中...</Text>
</View>
) : currentCardGroup?.cards.length ? (
<View className='bound-card-list cards-modal-list'>
{currentCardGroup.cards.map((card) => (
<View className='bound-card-item' key={`${currentCardGroup.device_id}-${card.card_id}`}>
<View className='bound-card-main'>
<Text className={`bound-card-name ${card.card_name ? '' : 'empty'}`}>
{card.card_name || '未命名卡片'}
</Text>
<Text className='bound-card-uuid'>{card.card_uuid}</Text>
</View>
{canEditCardName && (
<Text className='bound-card-edit' onClick={() => handleOpenCardNameModal(card)}>
编辑
</Text>
)}
</View>
))}
</View>
) : (
<View className='bound-cards-empty'>
<Text className='bound-cards-empty-text'>当前设备暂无卡片</Text>
</View>
)}
{binding?.device_id && (
<View className='cards-modal-add' onClick={handleOpenAddCard}>
<Text className='cards-modal-add-text'>添加设备卡片</Text>
</View>
)}
<View className='modal-actions'>
<Text className='modal-action cancel' onClick={() => setShowCardsModal(false)}>
关闭
</Text>
</View>
</View>
</View>
)}
{showModal && (
<View className='modal-mask'>
<View className='modal-card'>
<Text className='modal-title'>修改儿童昵称</Text>
<Text className='modal-title'>修改宝贝昵称</Text>
<View className='modal-input-wrap'>
<Input
className='modal-input'
value={childName}
placeholder='请输入儿童昵称'
placeholder='请输入宝贝昵称'
focus
onInput={(event) => setChildName(event.detail.value)}
/>