支持普通链接二维码进入绑定页
This commit is contained in:
@@ -26,6 +26,50 @@ const SESSION_STATUS_COMPLETED = 2
|
|||||||
const SESSION_STATUS_EXPIRED = 3
|
const SESSION_STATUS_EXPIRED = 3
|
||||||
const SESSION_STATUS_FAILED = 4
|
const SESSION_STATUS_FAILED = 4
|
||||||
const SESSION_STATUS_CANCELLED = 5
|
const SESSION_STATUS_CANCELLED = 5
|
||||||
|
const BIND_PAGE_URL = '/pages/bind/index'
|
||||||
|
|
||||||
|
function safeDecodeURIComponent(value: string): string {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(value)
|
||||||
|
} catch (error) {
|
||||||
|
console.log('[bind] decode uri component failed:', error)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeQueryComponent(value: string): string {
|
||||||
|
return safeDecodeURIComponent(value.replace(/\+/g, ' '))
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLaunchQrValue(value: string): string {
|
||||||
|
let decoded = String(value || '').trim()
|
||||||
|
for (let index = 0; index < 2; index += 1) {
|
||||||
|
const nextDecoded = safeDecodeURIComponent(decoded).trim()
|
||||||
|
if (nextDecoded === decoded) break
|
||||||
|
decoded = nextDecoded
|
||||||
|
}
|
||||||
|
return decoded
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRouteParam(params: Record<string, unknown> | undefined, key: string): string {
|
||||||
|
const value = params?.[key]
|
||||||
|
if (Array.isArray(value)) return String(value[0] || '').trim()
|
||||||
|
return String(value || '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPageUrl(pagePath: string, params: Record<string, unknown> | undefined): string {
|
||||||
|
const query = Object.entries(params || {})
|
||||||
|
.filter(([key, value]) => key && value !== undefined && value !== null && value !== '')
|
||||||
|
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
||||||
|
.join('&')
|
||||||
|
|
||||||
|
return query ? `${pagePath}?${query}` : pagePath
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLaunchQrPayload(params: Record<string, unknown> | undefined): string {
|
||||||
|
const qParam = getRouteParam(params, 'q')
|
||||||
|
return qParam ? decodeLaunchQrValue(qParam) : ''
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeExpiresAt(expiresAt: string): string {
|
function normalizeExpiresAt(expiresAt: string): string {
|
||||||
let normalized = String(expiresAt || '').trim()
|
let normalized = String(expiresAt || '').trim()
|
||||||
@@ -71,7 +115,7 @@ function parseBindingPayload(rawValue: string): { deviceId: string; serialNumber
|
|||||||
const pairMap = queryPart.split('&').reduce<Record<string, string>>((result, item) => {
|
const pairMap = queryPart.split('&').reduce<Record<string, string>>((result, item) => {
|
||||||
const [key, ...restValue] = item.split('=')
|
const [key, ...restValue] = item.split('=')
|
||||||
if (!key) return result
|
if (!key) return result
|
||||||
result[decodeURIComponent(key)] = decodeURIComponent(restValue.join('=') || '')
|
result[decodeQueryComponent(key)] = decodeQueryComponent(restValue.join('=') || '')
|
||||||
return result
|
return result
|
||||||
}, {})
|
}, {})
|
||||||
const deviceId = pairMap.device_id || pairMap.deviceId || ''
|
const deviceId = pairMap.device_id || pairMap.deviceId || ''
|
||||||
@@ -128,6 +172,7 @@ export default function Bind() {
|
|||||||
const [remainingBindSeconds, setRemainingBindSeconds] = useState(0)
|
const [remainingBindSeconds, setRemainingBindSeconds] = useState(0)
|
||||||
const pollingRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const pollingRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||||
|
const appliedLaunchQrRef = useRef('')
|
||||||
|
|
||||||
useDidShow(() => {
|
useDidShow(() => {
|
||||||
void loadPageData()
|
void loadPageData()
|
||||||
@@ -200,6 +245,27 @@ export default function Bind() {
|
|||||||
setRemainingBindSeconds(0)
|
setRemainingBindSeconds(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const applyLaunchQrPayload = () => {
|
||||||
|
if (isAssignMode) return false
|
||||||
|
|
||||||
|
const launchPayload = getLaunchQrPayload(router.params)
|
||||||
|
if (!launchPayload || appliedLaunchQrRef.current === launchPayload) return false
|
||||||
|
|
||||||
|
appliedLaunchQrRef.current = launchPayload
|
||||||
|
const parsed = parseBindingPayload(launchPayload)
|
||||||
|
if (!parsed.deviceId && !parsed.serialNumber) return false
|
||||||
|
|
||||||
|
resetBindSessionState()
|
||||||
|
if (parsed.deviceId) setDeviceId(parsed.deviceId)
|
||||||
|
if (parsed.serialNumber) setSerialNumber(parsed.serialNumber)
|
||||||
|
setBindHint(
|
||||||
|
parsed.serialNumber
|
||||||
|
? '已读取设备二维码信息,请选择儿童后发送绑卡指令'
|
||||||
|
: '已读取设备号,请补充设备序列号'
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const resetExpiredBindSession = (showToast = true) => {
|
const resetExpiredBindSession = (showToast = true) => {
|
||||||
stopPolling()
|
stopPolling()
|
||||||
stopCountdown()
|
stopCountdown()
|
||||||
@@ -300,6 +366,7 @@ export default function Bind() {
|
|||||||
|
|
||||||
const loadPageData = async () => {
|
const loadPageData = async () => {
|
||||||
if (!getToken()) {
|
if (!getToken()) {
|
||||||
|
Taro.setStorageSync('postLoginRedirect', buildPageUrl(BIND_PAGE_URL, router.params))
|
||||||
Taro.reLaunch({ url: '/pages/login/index' })
|
Taro.reLaunch({ url: '/pages/login/index' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -317,6 +384,7 @@ export default function Bind() {
|
|||||||
setDeviceId(activeBinding.device_id)
|
setDeviceId(activeBinding.device_id)
|
||||||
} else {
|
} else {
|
||||||
setPendingDeviceId(null)
|
setPendingDeviceId(null)
|
||||||
|
applyLaunchQrPayload()
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('[bind] load failed:', error)
|
console.error('[bind] load failed:', error)
|
||||||
|
|||||||
Reference in New Issue
Block a user