支持已绑定设备追加 NFC 卡
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
resolveActiveBinding,
|
||||
setBindingChild,
|
||||
setSelectedBindingDeviceId,
|
||||
startNFCCardBind,
|
||||
startNFCBind,
|
||||
} from '@/services/binding'
|
||||
import {
|
||||
@@ -154,6 +155,8 @@ function parseBindingPayload(rawValue: string): { deviceId: string; serialNumber
|
||||
export default function Bind() {
|
||||
const router = useRouter()
|
||||
const isAssignMode = String(router.params?.mode || '').trim() === 'assign'
|
||||
const isCardMode = String(router.params?.mode || '').trim() === 'card'
|
||||
const cardModeDeviceId = getRouteParam(router.params, 'device_id')
|
||||
const systemBanner = useSystemBanner()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
@@ -192,10 +195,12 @@ export default function Bind() {
|
||||
|
||||
const hasSelectedOrNewChild = selectedChildId !== null || Boolean(newChildName.trim())
|
||||
const isPendingBinding = Boolean(pendingDeviceId)
|
||||
const isAddingCard = isCardMode && Boolean(deviceId.trim())
|
||||
const isPollingBind = bindStatus === SESSION_STATUS_PENDING && Boolean(bindToken)
|
||||
const isExpiredBind = bindStatus === SESSION_STATUS_EXPIRED
|
||||
const canEditDeviceFields = !isPendingBinding && !isPollingBind
|
||||
const canSubmit = isPendingBinding ? hasSelectedOrNewChild : isExpiredBind ? true : !isPollingBind
|
||||
const pageTitle = isPendingBinding ? '补全绑定' : isAddingCard ? '添加设备卡' : '扫码贴卡绑定设备'
|
||||
|
||||
const goDevicePage = () => {
|
||||
Taro.reLaunch({ url: '/pages/device/index' })
|
||||
@@ -246,7 +251,7 @@ export default function Bind() {
|
||||
}
|
||||
|
||||
const applyLaunchQrPayload = () => {
|
||||
if (isAssignMode) return false
|
||||
if (isAssignMode || isCardMode) return false
|
||||
|
||||
const launchPayload = getLaunchQrPayload(router.params)
|
||||
if (!launchPayload || appliedLaunchQrRef.current === launchPayload) return false
|
||||
@@ -274,12 +279,14 @@ export default function Bind() {
|
||||
setCardUUID('')
|
||||
setBindExpiresAt('')
|
||||
setRemainingBindSeconds(0)
|
||||
setDeviceId('')
|
||||
setSerialNumber('')
|
||||
setBindHint('贴卡时间已过,请重新扫码并贴卡')
|
||||
if (!isCardMode) {
|
||||
setDeviceId('')
|
||||
setSerialNumber('')
|
||||
}
|
||||
setBindHint(isCardMode ? '贴卡时间已过,请重新发送加卡指令' : '贴卡时间已过,请重新扫码并贴卡')
|
||||
|
||||
if (showToast) {
|
||||
Taro.showToast({ title: '贴卡已超时,请重新扫码', icon: 'none' })
|
||||
Taro.showToast({ title: isCardMode ? '贴卡已超时,请重新发送' : '贴卡已超时,请重新扫码', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +325,7 @@ export default function Bind() {
|
||||
resetExpiredBindSession()
|
||||
return
|
||||
}
|
||||
setBindHint('已发送绑卡指令,请在倒计时结束前去设备上贴自己的卡')
|
||||
setBindHint(isAddingCard ? '已发送加卡指令,请在倒计时结束前去设备上贴新卡' : '已发送绑卡指令,请在倒计时结束前去设备上贴自己的卡')
|
||||
schedulePoll(activeBindToken)
|
||||
return
|
||||
}
|
||||
@@ -329,13 +336,15 @@ export default function Bind() {
|
||||
if (session.status === SESSION_STATUS_COMPLETED) {
|
||||
setSelectedBindingDeviceId(session.device_id)
|
||||
setBindHint(
|
||||
session.child_id
|
||||
isAddingCard
|
||||
? session.card_uuid ? `新卡添加完成,卡号 ${session.card_uuid}` : '新卡添加完成'
|
||||
: session.child_id
|
||||
? session.card_uuid ? `绑定完成,卡号 ${session.card_uuid}` : '绑定完成'
|
||||
: session.card_uuid ? `绑定完成,卡号 ${session.card_uuid},稍后可关联孩子` : '绑定完成,稍后可关联孩子'
|
||||
)
|
||||
Taro.showToast({ title: '设备绑定成功', icon: 'success' })
|
||||
Taro.showToast({ title: isAddingCard ? '新卡添加成功' : '设备绑定成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
if (session.child_id) {
|
||||
if (isAddingCard || session.child_id) {
|
||||
goDevicePage()
|
||||
} else {
|
||||
goManagePage()
|
||||
@@ -350,7 +359,7 @@ export default function Bind() {
|
||||
}
|
||||
|
||||
if (session.status === SESSION_STATUS_FAILED) {
|
||||
setBindHint('贴卡绑定失败,请重试')
|
||||
setBindHint(isAddingCard ? '添加新卡失败,请确认卡未绑定到其他设备后重试' : '贴卡绑定失败,请重试')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -379,7 +388,16 @@ export default function Bind() {
|
||||
setChildren(currentChildren)
|
||||
setSelectedChildId(currentChild?.child_id || null)
|
||||
|
||||
if (isAssignMode && activeBinding?.device_id && !activeBinding.child_id) {
|
||||
if (isCardMode) {
|
||||
const targetDeviceId = cardModeDeviceId || activeBinding?.device_id || ''
|
||||
if (!targetDeviceId) {
|
||||
throw new Error('当前没有可加卡的设备')
|
||||
}
|
||||
setPendingDeviceId(null)
|
||||
setDeviceId(targetDeviceId)
|
||||
setSerialNumber('')
|
||||
setBindHint('确认当前设备后发送加卡指令')
|
||||
} else if (isAssignMode && activeBinding?.device_id && !activeBinding.child_id) {
|
||||
setPendingDeviceId(activeBinding.device_id)
|
||||
setDeviceId(activeBinding.device_id)
|
||||
} else {
|
||||
@@ -451,10 +469,10 @@ export default function Bind() {
|
||||
if (submitting || isPollingBind) return
|
||||
|
||||
setSubmitting(true)
|
||||
Taro.showLoading({ title: isPendingBinding ? '关联中...' : '发送绑卡指令...' })
|
||||
Taro.showLoading({ title: isPendingBinding ? '关联中...' : isAddingCard ? '发送加卡指令...' : '发送绑卡指令...' })
|
||||
|
||||
try {
|
||||
const childId = await ensureChildId()
|
||||
const childId = isAddingCard ? null : await ensureChildId()
|
||||
|
||||
if (isPendingBinding) {
|
||||
if (!childId) {
|
||||
@@ -472,6 +490,19 @@ export default function Bind() {
|
||||
if (!deviceId.trim()) {
|
||||
throw new Error('请输入设备号')
|
||||
}
|
||||
if (isAddingCard) {
|
||||
resetBindSessionState()
|
||||
const session = await startNFCCardBind({ device_id: deviceId.trim() })
|
||||
|
||||
setBindToken(session.bind_token)
|
||||
setBindStatus(session.status)
|
||||
setBindExpiresAt(session.expires_at)
|
||||
setRemainingBindSeconds(getRemainingBindSeconds(session.expires_at))
|
||||
setBindHint('已发送加卡指令,请在倒计时结束前去设备上贴新卡')
|
||||
schedulePoll(session.bind_token)
|
||||
Taro.showToast({ title: '请去设备上贴新卡', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!serialNumber.trim()) {
|
||||
throw new Error('请输入设备序列号')
|
||||
}
|
||||
@@ -521,10 +552,19 @@ export default function Bind() {
|
||||
<Image className='back-icon' src={require('../../assets/tab-icons/arrow-left.png')} mode='aspectFit' />
|
||||
<Text className='back-text'>返回</Text>
|
||||
</View>
|
||||
<Text className='title'>{isPendingBinding ? '补全绑定' : '扫码贴卡绑定设备'}</Text>
|
||||
<Text className='title'>{pageTitle}</Text>
|
||||
</View>
|
||||
|
||||
{isPendingBinding ? (
|
||||
{isAddingCard ? (
|
||||
<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='pending-device-title'>给当前设备添加卡</Text>
|
||||
<Text className='pending-device-id'>{deviceId}</Text>
|
||||
<Text className='pending-device-desc'>新卡添加后会和已有卡具备相同功能</Text>
|
||||
</View>
|
||||
) : 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' />
|
||||
@@ -555,6 +595,7 @@ export default function Bind() {
|
||||
)}
|
||||
|
||||
<View className='bind-form'>
|
||||
{!isAddingCard && (
|
||||
<View className='form-card'>
|
||||
<Text className='form-title'>儿童资料</Text>
|
||||
|
||||
@@ -621,22 +662,24 @@ export default function Bind() {
|
||||
: '也可以先不创建儿童,直接绑定设备,稍后再关联孩子'}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{!isPendingBinding && (
|
||||
<View className='form-card'>
|
||||
<Text className='form-title'>设备信息</Text>
|
||||
<Text className='form-title'>{isAddingCard ? '加卡状态' : '设备信息'}</Text>
|
||||
|
||||
<View className='field-item'>
|
||||
<Text className='field-label'>设备号</Text>
|
||||
<Input
|
||||
className='field-input'
|
||||
value={deviceId}
|
||||
disabled={!canEditDeviceFields || isPendingBinding}
|
||||
placeholder={canEditDeviceFields ? '请输入设备号' : '绑定确认中'}
|
||||
disabled={isAddingCard || !canEditDeviceFields || isPendingBinding}
|
||||
placeholder={isAddingCard ? '当前设备' : canEditDeviceFields ? '请输入设备号' : '绑定确认中'}
|
||||
onInput={(event) => setDeviceId(event.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{!isAddingCard && (
|
||||
<View className='field-item'>
|
||||
<Text className='field-label'>设备序列号</Text>
|
||||
<Input
|
||||
@@ -647,6 +690,7 @@ export default function Bind() {
|
||||
onInput={(event) => setSerialNumber(event.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{bindHint ? (
|
||||
<View className='pending-tip'>
|
||||
@@ -670,9 +714,15 @@ export default function Bind() {
|
||||
className='submit-btn'
|
||||
loading={submitting}
|
||||
disabled={submitting || !canSubmit}
|
||||
onClick={isExpiredBind && !isPendingBinding ? handleScanCode : handleSubmit}
|
||||
onClick={isExpiredBind && !isPendingBinding && !isAddingCard ? handleScanCode : handleSubmit}
|
||||
>
|
||||
{isPendingBinding ? '完成儿童关联' : isPollingBind ? '等待贴卡确认' : isExpiredBind ? '重新扫码绑定' : '发送绑卡指令'}
|
||||
{isPendingBinding
|
||||
? '完成儿童关联'
|
||||
: isPollingBind
|
||||
? '等待贴卡确认'
|
||||
: isExpiredBind
|
||||
? isAddingCard ? '重新发送加卡指令' : '重新扫码绑定'
|
||||
: isAddingCard ? '发送加卡指令' : '发送绑卡指令'}
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
@@ -680,15 +730,15 @@ export default function Bind() {
|
||||
<Text className='tips-title'>绑定帮助</Text>
|
||||
<View className='tip-item'>
|
||||
<Text className='tip-number'>1</Text>
|
||||
<Text className='tip-text'>{isPendingBinding ? '先选择已有儿童,或者在本页新建一个儿童' : '儿童资料可选,不选择时设备会先进入待关联状态'}</Text>
|
||||
<Text className='tip-text'>{isAddingCard ? '确认当前设备号正确' : isPendingBinding ? '先选择已有儿童,或者在本页新建一个儿童' : '儿童资料可选,不选择时设备会先进入待关联状态'}</Text>
|
||||
</View>
|
||||
<View className='tip-item'>
|
||||
<Text className='tip-number'>2</Text>
|
||||
<Text className='tip-text'>{isPendingBinding ? '确认当前待关联设备,再选择要关联的孩子' : '扫描设备二维码,确认设备号和序列号正确'}</Text>
|
||||
<Text className='tip-text'>{isAddingCard ? '点击发送加卡指令后,在设备上贴新卡' : isPendingBinding ? '确认当前待关联设备,再选择要关联的孩子' : '扫描设备二维码,确认设备号和序列号正确'}</Text>
|
||||
</View>
|
||||
<View className='tip-item'>
|
||||
<Text className='tip-number'>3</Text>
|
||||
<Text className='tip-text'>{isPendingBinding ? '点击完成儿童关联,设备会出现在该孩子下面' : '点击发送绑卡指令,然后在 10 分钟内去设备上贴自己的卡完成确认'}</Text>
|
||||
<Text className='tip-text'>{isAddingCard ? '加卡成功后,新卡和原来的卡可以执行相同功能' : isPendingBinding ? '点击完成儿童关联,设备会出现在该孩子下面' : '点击发送绑卡指令,然后在 10 分钟内去设备上贴自己的卡完成确认'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
{systemBanner}
|
||||
|
||||
@@ -614,6 +614,12 @@ 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)}` })
|
||||
return
|
||||
}
|
||||
|
||||
if (item.name === 'AI 角色') {
|
||||
handleOpenRoleModal()
|
||||
return
|
||||
@@ -713,6 +719,14 @@ export default function Sleep() {
|
||||
value: binding?.device_id ? `当前: ${binding.device_id}` : '未绑定',
|
||||
arrow: true,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '添加设备卡',
|
||||
value: binding?.device_id ? '给当前设备加卡' : '未绑定',
|
||||
arrow: true,
|
||||
disabled: !binding,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/orange-robot.png'),
|
||||
iconBgClass: 'green',
|
||||
|
||||
Reference in New Issue
Block a user