From b4fef6d2e0a91fc6319bd8b6068869879b4b8b08 Mon Sep 17 00:00:00 2001 From: stu2not Date: Thu, 2 Jul 2026 11:43:09 +0800 Subject: [PATCH] Refine device-first baby management --- banban-mini/src/pages/bind/index.tsx | 38 +-- banban-mini/src/pages/chat/detail/index.tsx | 2 +- banban-mini/src/pages/chat/index.tsx | 4 +- banban-mini/src/pages/device/index.tsx | 36 +-- banban-mini/src/pages/location/index.tsx | 20 +- banban-mini/src/pages/login/index.tsx | 2 +- .../src/pages/sleep-schedule/index.tsx | 8 +- banban-mini/src/pages/sleep/index.scss | 54 ++++ banban-mini/src/pages/sleep/index.tsx | 276 ++++++++++-------- banban-mini/src/services/chat.ts | 32 +- banban-mini/src/services/system-banner.ts | 4 +- 11 files changed, 275 insertions(+), 201 deletions(-) diff --git a/banban-mini/src/pages/bind/index.tsx b/banban-mini/src/pages/bind/index.tsx index df6a7ba..0d787be 100644 --- a/banban-mini/src/pages/bind/index.tsx +++ b/banban-mini/src/pages/bind/index.tsx @@ -201,7 +201,7 @@ export default function Bind() { const isExpiredBind = bindStatus === SESSION_STATUS_EXPIRED const canEditDeviceFields = !isPendingBinding && !isPollingBind const canSubmit = isPendingBinding ? hasSelectedOrNewChild : isExpiredBind ? true : !isPollingBind - const pageTitle = isPendingBinding ? '补全绑定' : isAddingCard ? '添加设备卡' : '扫码贴卡绑定设备' + const pageTitle = isPendingBinding ? '补全绑定' : isAddingCard ? '添加设备卡片' : '扫码贴卡绑定设备' const goDevicePage = () => { Taro.reLaunch({ url: '/pages/device/index' }) @@ -286,7 +286,7 @@ export default function Bind() { if (parsed.serialNumber) setSerialNumber(parsed.serialNumber) setBindHint( parsed.serialNumber - ? '已读取设备二维码信息,请选择儿童后发送绑卡指令' + ? '已读取设备二维码信息,请选择宝贝后发送绑卡指令' : '已读取设备号,请补充设备序列号' ) return true @@ -364,7 +364,7 @@ export default function Bind() { ? session.card_uuid ? `新卡添加完成,卡号 ${session.card_uuid}` : '新卡添加完成' : session.child_id ? session.card_uuid ? `绑定完成,卡号 ${session.card_uuid}` : '绑定完成' - : session.card_uuid ? `绑定完成,卡号 ${session.card_uuid},稍后可关联孩子` : '绑定完成,稍后可关联孩子' + : session.card_uuid ? `绑定完成,卡号 ${session.card_uuid},稍后可关联宝贝` : '绑定完成,稍后可关联宝贝' ) Taro.showToast({ title: isAddingCard ? '新卡添加成功' : '设备绑定成功', icon: 'success' }) setTimeout(() => { @@ -500,7 +500,7 @@ export default function Bind() { if (isPendingBinding) { if (!childId) { - throw new Error('请先选择儿童或填写新的儿童昵称') + throw new Error('请先选择宝贝或填写新的宝贝昵称') } await setBindingChild(pendingDeviceId!, { child_id: childId }) setSelectedBindingDeviceId(pendingDeviceId) @@ -585,7 +585,7 @@ export default function Bind() { - 给当前设备添加卡 + 给当前设备添加卡片 {deviceId} 新卡添加后会和已有卡具备相同功能 @@ -596,7 +596,7 @@ export default function Bind() { 关联现有设备 {pendingDeviceId} - 选择已有孩子,或新建孩子后完成关联 + 选择已有宝贝,或新建宝贝后完成关联 ) : ( @@ -622,7 +622,7 @@ export default function Bind() { {!isAddingCard && ( - 儿童资料 + 宝贝资料 {children.length > 0 && ( @@ -635,7 +635,7 @@ export default function Bind() { setNewChildName('') }} > - 暂不关联孩子 + 暂不关联宝贝 )} {children.map((child) => ( @@ -658,14 +658,14 @@ export default function Bind() { )} - {isPendingBinding ? '新建儿童昵称' : '新建儿童昵称(可选)'} + {isPendingBinding ? '新建宝贝昵称' : '新建宝贝昵称(可选)'} 0 ? '不选已有儿童时,可填写新昵称' : '请输入儿童昵称' - : children.length > 0 ? '不选已有儿童时,可填写新昵称' : '可不填,稍后再关联孩子' + ? children.length > 0 ? '不选已有宝贝时,可填写新昵称' : '请输入宝贝昵称' + : children.length > 0 ? '不选已有宝贝时,可填写新昵称' : '可不填,稍后再关联宝贝' } onInput={(event) => { setNewChildName(event.detail.value) @@ -680,11 +680,11 @@ export default function Bind() { {isPendingBinding ? children.length > 0 - ? '可以选已有儿童,也可以新建一个儿童后关联当前设备' - : '当前还没有儿童资料,请先创建一个儿童资料后关联设备' + ? '可以选已有宝贝,也可以新建一个宝贝后关联当前设备' + : '当前还没有宝贝资料,请先创建一个宝贝资料后关联设备' : children.length > 0 - ? '儿童资料可选;不选择时,设备会先绑定到账号,稍后可关联孩子' - : '也可以先不创建儿童,直接绑定设备,稍后再关联孩子'} + ? '宝贝资料可选;不选择时,设备会先绑定到账号,稍后可关联宝贝' + : '也可以先不创建宝贝,直接绑定设备,稍后再关联宝贝'} )} @@ -742,7 +742,7 @@ export default function Bind() { onClick={isExpiredBind && !isPendingBinding && !isAddingCard ? handleScanCode : handleSubmit} > {isPendingBinding - ? '完成儿童关联' + ? '完成宝贝关联' : isPollingBind ? '等待贴卡确认' : isExpiredBind @@ -755,15 +755,15 @@ export default function Bind() { 绑定帮助 1 - {isAddingCard ? '确认当前设备号正确' : isPendingBinding ? '先选择已有儿童,或者在本页新建一个儿童' : '儿童资料可选,不选择时设备会先进入待关联状态'} + {isAddingCard ? '确认当前设备号正确' : isPendingBinding ? '先选择已有宝贝,或者在本页新建一个宝贝' : '宝贝资料可选,不选择时设备会先进入待关联状态'} 2 - {isAddingCard ? '点击发送加卡指令后,在设备上贴新卡' : isPendingBinding ? '确认当前待关联设备,再选择要关联的孩子' : '扫描设备二维码,确认设备号和序列号正确'} + {isAddingCard ? '点击发送加卡指令后,在设备上贴新卡' : isPendingBinding ? '确认当前待关联设备,再选择要关联的宝贝' : '扫描设备二维码,确认设备号和序列号正确'} 3 - {isAddingCard ? '加卡成功后,新卡和原来的卡可以执行相同功能' : isPendingBinding ? '点击完成儿童关联,设备会出现在该孩子下面' : '点击发送绑卡指令,然后在 10 分钟内去设备上贴自己的卡完成确认'} + {isAddingCard ? '加卡成功后,新卡和原来的卡可以执行相同功能' : isPendingBinding ? '点击完成宝贝关联,设备会出现在该宝贝下面' : '点击发送绑卡指令,然后在 10 分钟内去设备上贴自己的卡完成确认'} {systemBanner} diff --git a/banban-mini/src/pages/chat/detail/index.tsx b/banban-mini/src/pages/chat/detail/index.tsx index 4a14443..2f11672 100644 --- a/banban-mini/src/pages/chat/detail/index.tsx +++ b/banban-mini/src/pages/chat/detail/index.tsx @@ -37,7 +37,7 @@ function formatParticipantLabel(message: ChatMessage): string { return name === '我' ? '我' : name || '家长' } if (senderType === 'child') { - return name || `儿童ID ${senderId}` + return name || `宝贝ID ${senderId}` } if (senderType === 'device') { return name || `设备ID ${senderId}` diff --git a/banban-mini/src/pages/chat/index.tsx b/banban-mini/src/pages/chat/index.tsx index 5fdcfaf..9c40e9a 100644 --- a/banban-mini/src/pages/chat/index.tsx +++ b/banban-mini/src/pages/chat/index.tsx @@ -74,7 +74,7 @@ export default function Chat() { 💬 亲子互动会话 - 绑定设备后,可以在这里查看孩子、家长和 AI 玩伴之间的消息记录。 + 绑定设备后,可以在这里查看宝贝、家长和 AI 玩伴之间的消息记录。 登录后查看 @@ -85,7 +85,7 @@ export default function Chat() { ) : conversations.length === 0 ? ( - 当前孩子暂无会话 + 当前宝贝暂无会话 ) : ( diff --git a/banban-mini/src/pages/device/index.tsx b/banban-mini/src/pages/device/index.tsx index 5ab2c36..0c3849a 100644 --- a/banban-mini/src/pages/device/index.tsx +++ b/banban-mini/src/pages/device/index.tsx @@ -93,8 +93,8 @@ function getAlarmChildLabel(alarm: DeviceAlarmItem | null, fallbackChildName?: s const fallbackName = String(fallbackChildName || '').trim() if (fallbackName) return fallbackName - if (alarm?.child_id) return `儿童 ${alarm.child_id}` - return '未关联儿童' + if (alarm?.child_id) return `宝贝 ${alarm.child_id}` + return '未关联宝贝' } function formatAlarmCoordinates(alarm: DeviceAlarmItem | null): string { @@ -287,7 +287,7 @@ export default function Device() { - 伴伴儿童陪伴设备 + 伴伴宝贝陪伴设备 查看设备状态、定位轨迹、亲子消息和休眠管理。浏览功能后,可在需要绑定设备时登录。 @@ -305,18 +305,18 @@ export default function Device() { 亲子互动 - 查看孩子和设备的消息会话。 + 查看宝贝和设备的消息会话。 设备管理 - 管理孩子资料、绑定设备和休眠设置。 + 管理宝贝资料、绑定设备和休眠设置。 准备绑定或管理设备 - 登录后可绑定设备,并在绑定流程中创建或选择孩子资料。 + 登录后可绑定设备,并在绑定流程中创建或选择宝贝资料。 goLoginWithRedirect('/pages/device/index')}> 登录后继续 @@ -338,14 +338,14 @@ export default function Device() { - {hasPendingDevice ? '设备已绑定,待关联孩子' : '先绑定一台伴伴设备'} + {hasPendingDevice ? '设备已绑定,待关联宝贝' : '先绑定一台伴伴设备'} {hasPendingDevice - ? '这台设备还没有关联孩子,关联后即可查看定位、聊天和设备状态' - : '绑定时可以选择已有孩子,或直接新建孩子昵称'} + ? '这台设备还没有关联宝贝,关联后即可查看定位、聊天和设备状态' + : '绑定时可以选择已有宝贝,或直接新建宝贝昵称'} Taro.navigateTo({ url: hasPendingDevice ? '/pages/bind/index?mode=assign' : '/pages/bind/index' })}> - {hasPendingDevice ? '关联孩子' : '添加设备'} + {hasPendingDevice ? '关联宝贝' : '添加设备'} {systemBanner} @@ -367,7 +367,7 @@ export default function Device() { {child.child_name} - 当前孩子已选中,还没有绑定设备 + 当前宝贝已选中,还没有绑定设备 @@ -375,14 +375,14 @@ export default function Device() { - {hasPendingDevice ? '有设备待关联' : '给当前孩子绑定一台设备'} + {hasPendingDevice ? '有设备待关联' : '给当前宝贝绑定一台设备'} {hasPendingDevice - ? `设备 ${pendingBinding?.device_id} 还没有关联孩子,可以关联到当前孩子` - : '绑定后,这个孩子的聊天记录、定位和设备状态都会显示在首页'} + ? `设备 ${pendingBinding?.device_id} 还没有关联宝贝,可以关联到当前宝贝` + : '绑定后,这个宝贝的聊天记录、定位和设备状态都会显示在首页'} Taro.navigateTo({ url: hasPendingDevice ? '/pages/bind/index?mode=assign' : '/pages/bind/index' })}> - {hasPendingDevice ? '关联到当前孩子' : '去绑定设备'} + {hasPendingDevice ? '关联到当前宝贝' : '去绑定设备'} {systemBanner} @@ -550,7 +550,7 @@ export default function Device() { {formatAlarmTime(latestAlarm.created_at)} - 来源儿童 + 来源宝贝 {latestAlarmChildName} @@ -585,7 +585,7 @@ export default function Device() { - 来源儿童:{getAlarmChildLabel(alarm, childName)} + 来源宝贝:{getAlarmChildLabel(alarm, childName)} {alarm.device_id} @@ -621,7 +621,7 @@ export default function Device() { {isDetailExpanded && ( - 当前儿童 + 当前宝贝 {childName} diff --git a/banban-mini/src/pages/location/index.tsx b/banban-mini/src/pages/location/index.tsx index 7820f53..69ef400 100644 --- a/banban-mini/src/pages/location/index.tsx +++ b/banban-mini/src/pages/location/index.tsx @@ -66,7 +66,7 @@ function buildLocationDetailLines( const lines: string[] = [] if (options?.includeIdentity) { - lines.push(`设备 ${point.device_id} · ${point.child_name || '未命名儿童'}`) + lines.push(`设备 ${point.device_id} · ${point.child_name || '未命名宝贝'}`) } lines.push(`上报时间 ${formatTime(point.device_time)}`) @@ -177,10 +177,10 @@ export default function Location() { setSelectedPoint(null) setCoordinates(DEFAULT_COORDINATES) setEmptyState({ - title: '还没有当前孩子', - desc: '请先去设置与管理页创建或选择一个孩子,再查看定位。', - actionText: '去设置与管理', - actionUrl: '/pages/sleep/index', + title: '还没有当前宝贝', + desc: '请先绑定设备,并在绑定流程中创建或选择宝贝,再查看定位。', + actionText: '去绑定设备', + actionUrl: '/pages/bind/index', }) return } @@ -192,8 +192,8 @@ export default function Location() { setSelectedPoint(null) setCoordinates(DEFAULT_COORDINATES) setEmptyState({ - title: '当前孩子还没有绑定设备', - desc: '先给当前孩子绑定一台设备,定位和轨迹页才会有内容。', + title: '当前宝贝还没有绑定设备', + desc: '先给当前宝贝绑定一台设备,定位和轨迹页才会有内容。', actionText: '去绑定设备', actionUrl: '/pages/bind/index', }) @@ -397,7 +397,7 @@ export default function Location() { 设备定位与轨迹 - 绑定设备后,可在这里查看孩子设备的位置、更新时间和定位精度。 + 绑定设备后,可在这里查看宝贝设备的位置、更新时间和定位精度。 { @@ -501,7 +501,7 @@ export default function Location() { ) : ( - {locationNotice || '当前孩子暂无设备位置'} + {locationNotice || '当前宝贝暂无设备位置'} {locationNotice && 请确认设备已开机并保持网络可用。} ) @@ -545,7 +545,7 @@ export default function Location() { 暂无轨迹 - {trajectoryMode === 'today' ? '当前孩子今天还没有新的历史点位。' : '当前孩子最近没有新的历史点位。'} + {trajectoryMode === 'today' ? '当前宝贝今天还没有新的历史点位。' : '当前宝贝最近没有新的历史点位。'} )} diff --git a/banban-mini/src/pages/login/index.tsx b/banban-mini/src/pages/login/index.tsx index 9223009..e845391 100644 --- a/banban-mini/src/pages/login/index.tsx +++ b/banban-mini/src/pages/login/index.tsx @@ -153,7 +153,7 @@ export default function Login() { 登录后启用设备管理 - 仅在绑定设备、查看定位和管理孩子资料时需要登录。 + 仅在绑定设备、查看定位和管理宝贝资料时需要登录。 diff --git a/banban-mini/src/pages/sleep-schedule/index.tsx b/banban-mini/src/pages/sleep-schedule/index.tsx index ef4b5b3..b644599 100644 --- a/banban-mini/src/pages/sleep-schedule/index.tsx +++ b/banban-mini/src/pages/sleep-schedule/index.tsx @@ -121,11 +121,11 @@ export default function SleepSchedule() { 定时休眠 - 先选择一个孩子,再为对应设备设置休眠时间 + 先绑定设备并选择宝贝,再为对应设备设置休眠时间 - 还没有当前孩子 - 请先到管理页添加并选择孩子。 + 还没有当前宝贝 + 请先去首页绑定设备,并在绑定流程中创建或选择宝贝。 {systemBanner} @@ -153,7 +153,7 @@ export default function SleepSchedule() { const currentRange = formatSleepRange(deviceStatus) const timezoneText = deviceStatus?.timezone || 'Asia/Shanghai' - const childName = child.child_name || '当前孩子' + const childName = child.child_name || '当前宝贝' return ( diff --git a/banban-mini/src/pages/sleep/index.scss b/banban-mini/src/pages/sleep/index.scss index 22cf3bd..e18dae2 100644 --- a/banban-mini/src/pages/sleep/index.scss +++ b/banban-mini/src/pages/sleep/index.scss @@ -628,6 +628,10 @@ max-height: 74vh; } +.cards-modal-card { + max-height: 76vh; +} + .family-card { max-height: 76vh; } @@ -677,6 +681,46 @@ overflow-y: auto; } +.cards-modal-summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 18px; + padding: 18px 20px; + border-radius: 16px; + background: #F8FAFC; + margin-bottom: 18px; +} + +.cards-modal-device { + min-width: 0; + font-size: 26px; + color: #1F2937; + font-weight: 600; + word-break: break-all; +} + +.cards-modal-list { + max-height: 42vh; + overflow-y: auto; +} + +.cards-modal-add { + height: 84px; + margin-top: 22px; + border-radius: 18px; + background: #FFF2E7; + display: flex; + align-items: center; + justify-content: center; +} + +.cards-modal-add-text { + font-size: 28px; + color: #FF8C42; + font-weight: 700; +} + .device-switch-item { padding: 24px; border-radius: 18px; @@ -790,6 +834,16 @@ flex-shrink: 0; } +.device-switch-delete { + padding: 6px 14px; + border-radius: 999px; + background: #FFFFFF; + border: 2px solid #E5484D; + font-size: 22px; + color: #E5484D; + flex-shrink: 0; +} + .device-switch-name { font-size: 26px; color: #666666; diff --git a/banban-mini/src/pages/sleep/index.tsx b/banban-mini/src/pages/sleep/index.tsx index 2ed8c1c..ad9c578 100644 --- a/banban-mini/src/pages/sleep/index.tsx +++ b/banban-mini/src/pages/sleep/index.tsx @@ -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(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() { ⚙️ - 管理孩子资料和设备 - 登录后可创建孩子资料、绑定伴伴设备、管理卡片、设置休眠时间和家庭成员。 + 管理宝贝资料和设备 + 登录后可创建宝贝资料、绑定伴伴设备、管理卡片、设置休眠时间和家庭成员。 { @@ -966,8 +994,8 @@ export default function Sleep() { - 孩子资料 - 为不同孩子维护独立设备和会话。 + 宝贝资料 + 为不同宝贝维护独立设备和会话。 设备绑定 @@ -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() { - 儿童资料数 + 宝贝资料数 {children.length} 个 - 当前儿童 + 当前宝贝 {currentChildName} @@ -1197,50 +1222,6 @@ export default function Sleep() { - - - - 已绑卡片 - {binding?.device_id || '当前未绑定设备'} - - - {isLoadingCards ? '查询中' : `${currentCardGroup?.card_count || 0} 张`} - - - - {!binding?.device_id ? ( - - 绑定设备后可查看卡片 UUID - - ) : isLoadingCards ? ( - - 卡片加载中... - - ) : currentCardGroup?.cards.length ? ( - - {currentCardGroup.cards.map((card) => ( - - - - {card.card_name || '未命名卡片'} - - {card.card_uuid} - - {canEditCardName && ( - handleOpenCardNameModal(card)}> - 编辑 - - )} - - ))} - - ) : ( - - 当前设备暂无已绑卡片 - - )} - - {menuItems.map((item, index) => ( @@ -1279,9 +1260,9 @@ export default function Sleep() { event.stopPropagation() }} > - 切换当前孩子 + 切换当前宝贝 {children.length === 0 ? ( - 当前还没有儿童资料 + 当前还没有宝贝资料 ) : ( {children.map((item) => { @@ -1308,6 +1289,15 @@ export default function Sleep() { 修改 )} + { + event.stopPropagation() + handleDeleteChild(item) + }} + > + 删除 + {itemBinding?.device_id || '未绑定设备'} @@ -1325,50 +1315,6 @@ export default function Sleep() { )} - {showDeleteChildModal && ( - setShowDeleteChildModal(false)}> - { - event.stopPropagation() - }} - > - 选择要删除的孩子 - {children.length === 0 ? ( - 当前还没有儿童资料 - ) : ( - - {children.map((item) => { - const isActive = currentChild?.child_id === item.child_id - const itemBinding = bindings.find((bindingItem) => bindingItem.child_id === item.child_id) || null - return ( - handleDeleteChild(item)} - > - - {item.child_name} - - {isActive && 当前} - 删除 - - - {itemBinding?.device_id || '未绑定设备'} - - ) - })} - - )} - - setShowDeleteChildModal(false)}> - 关闭 - - - - - )} - {showAssignDeviceModal && ( setShowAssignDeviceModal(false)}> {item.device_id} - 待关联 + + 待关联 + { + event.stopPropagation() + handleDeleteUnassignedDevice(item) + }} + > + 删除 + + - 未关联孩子 + 未关联宝贝 ))} @@ -1406,15 +1363,78 @@ export default function Sleep() { )} + {showCardsModal && ( + setShowCardsModal(false)}> + { + event.stopPropagation() + }} + > + 我的卡片 + + {binding?.device_id || '当前未绑定设备'} + + {isLoadingCards ? '查询中' : `${currentCardGroup?.card_count || 0} 张`} + + + + {!binding?.device_id ? ( + + 绑定设备后可查看卡片 UUID + + ) : isLoadingCards ? ( + + 卡片加载中... + + ) : currentCardGroup?.cards.length ? ( + + {currentCardGroup.cards.map((card) => ( + + + + {card.card_name || '未命名卡片'} + + {card.card_uuid} + + {canEditCardName && ( + handleOpenCardNameModal(card)}> + 编辑 + + )} + + ))} + + ) : ( + + 当前设备暂无卡片 + + )} + + {binding?.device_id && ( + + 添加设备卡片 + + )} + + + setShowCardsModal(false)}> + 关闭 + + + + + )} + {showModal && ( - 修改儿童昵称 + 修改宝贝昵称 setChildName(event.detail.value)} /> diff --git a/banban-mini/src/services/chat.ts b/banban-mini/src/services/chat.ts index 4031117..a986c25 100644 --- a/banban-mini/src/services/chat.ts +++ b/banban-mini/src/services/chat.ts @@ -178,13 +178,13 @@ interface BindingContext { } const PEER_META: Record = { - child: { icon: '🧒', label: '儿童', description: '孩子正在交流的儿童玩伴' }, - parent: { icon: '👨', label: '家长', description: '家长通过微信小程序和孩子沟通' }, - ai: { icon: '🤖', label: 'AI', description: '孩子与 AI 的历史交流' }, + child: { icon: '🧒', label: '宝贝', description: '宝贝正在交流的玩伴' }, + parent: { icon: '👨', label: '家长', description: '家长通过微信小程序和宝贝沟通' }, + ai: { icon: '🤖', label: 'AI', description: '宝贝与 AI 的历史交流' }, } const AI_ROLE_META: Record = { - assistant: { name: 'AI', icon: '🤖', description: '孩子与 AI 的历史交流' }, + assistant: { name: 'AI', icon: '🤖', description: '宝贝与 AI 的历史交流' }, } type AiMeta = { name: string; icon: string; description: string } @@ -260,14 +260,14 @@ function getAiMeta(roleKey?: string, roleName?: string | null, roleDescription?: return { name: normalizedRoleName, icon: '🤖', - description: normalizedRoleDescription || `孩子与 ${normalizedRoleName} 的历史交流`, + description: normalizedRoleDescription || `宝贝与 ${normalizedRoleName} 的历史交流`, } } if (roleKey && AI_ROLE_META[roleKey]) return AI_ROLE_META[roleKey] return { name: roleKey || 'AI', icon: '🤖', - description: `孩子与 ${roleKey || 'AI'} 的历史交流`, + description: `宝贝与 ${roleKey || 'AI'} 的历史交流`, } } @@ -288,7 +288,7 @@ async function getRoleMetaMap(): Promise> { function getParticipantDisplayName(type: string, id?: string, name?: string | null): string { if (name && name.trim()) return name.trim() - if (type === 'child') return id ? `儿童 ${id}` : '儿童' + if (type === 'child') return id ? `宝贝 ${id}` : '宝贝' if (type === 'parent') return id ? `家长 ${id}` : '家长' return id || 'AI' } @@ -400,8 +400,8 @@ function toImConversation(item: ChildConversationItem, context: BindingContext): typeLabel: isParentConversation ? (canSend ? '家长沟通' : '留言记录') : meta.label, description: isParentConversation ? canSend - ? '家长通过微信小程序和孩子直接沟通' - : '其他家长和孩子的留言记录' + ? '家长通过微信小程序和宝贝直接沟通' + : '其他家长和宝贝的留言记录' : meta.description, lastMessage: item.last_message_preview || (isParentConversation ? (canSend ? '还没有消息,点进去发送第一条' : '暂无留言记录') : '暂无消息'), time: formatListTime(sortAt), @@ -457,7 +457,7 @@ function createSyntheticParentConversation(context: BindingContext): ChatConvers name: '家长沟通', avatar: PEER_META.parent.icon, typeLabel: '家长沟通', - description: '家长通过微信小程序和孩子直接沟通', + description: '家长通过微信小程序和宝贝直接沟通', lastMessage: '还没有留言,点进去发送第一条', time: '', sortAt: '', @@ -533,8 +533,8 @@ export async function getMessages( senderId: item.is_user ? context.deviceId : item.role_key, receiverType: item.is_user ? 'ai' : 'device', receiverId: item.is_user ? item.role_key : context.deviceId, - senderName: item.is_user ? context.childName || '孩子设备' : meta.name, - receiverName: item.is_user ? meta.name : context.childName || '孩子设备', + senderName: item.is_user ? context.childName || '宝贝设备' : meta.name, + receiverName: item.is_user ? meta.name : context.childName || '宝贝设备', channelLabel: 'AI', } }) @@ -569,13 +569,13 @@ export async function getMessages( item.sender_type === 'parent' && item.sender_id === String(context.currentUserId) ? '我' : item.sender_type === 'child' && item.sender_id === String(context.childId || '') - ? context.childName || item.sender_name_snapshot || '孩子' + ? context.childName || item.sender_name_snapshot || '宝贝' : getParticipantDisplayName(item.sender_type, item.sender_id, item.sender_name_snapshot), receiverName: item.receiver_type === 'parent' && item.receiver_id === String(context.currentUserId) ? '我' : item.receiver_type === 'child' && item.receiver_id === String(context.childId || '') - ? context.childName || item.receiver_name_snapshot || '孩子' + ? context.childName || item.receiver_name_snapshot || '宝贝' : getParticipantDisplayName(item.receiver_type, item.receiver_id, item.receiver_name_snapshot), channelLabel: isParentConversation && (item.sender_type === 'parent' || item.receiver_type === 'parent') @@ -644,7 +644,7 @@ export async function getCharacter(options: { return { id: conversationId, name: normalizedName, - description: canSendParentMessage ? '微信小程序 <-> 儿童设备' : '其他家长和孩子的留言记录', + description: canSendParentMessage ? '微信小程序 <-> 宝贝设备' : '其他家长和宝贝的留言记录', icon: PEER_META.parent.icon, peerKind: 'parent', source, @@ -663,7 +663,7 @@ export async function getCharacter(options: { return { id: conversationId, name: getPeerDisplayName(peerKind, peerId, name), - description: peerKind === 'child' ? '儿童设备间的聊天记录' : meta.description, + description: peerKind === 'child' ? '宝贝设备间的聊天记录' : meta.description, icon: meta.icon, peerKind, source, diff --git a/banban-mini/src/services/system-banner.ts b/banban-mini/src/services/system-banner.ts index 1d45b0f..fd540a1 100644 --- a/banban-mini/src/services/system-banner.ts +++ b/banban-mini/src/services/system-banner.ts @@ -53,8 +53,8 @@ function getAlarmChildLabel(alarm: DeviceAlarmItem, fallbackChildName?: string | const fallbackName = String(fallbackChildName || '').trim() if (fallbackName) return fallbackName - if (alarm.child_id) return `儿童 ${alarm.child_id}` - return '当前孩子' + if (alarm.child_id) return `宝贝 ${alarm.child_id}` + return '当前宝贝' } function getAlarmTypeLabel(sourceMsgId?: string | null): string {