From c4d977ce990afd41262ecb5558ee4fb57ddb7481 Mon Sep 17 00:00:00 2001 From: stu2not Date: Wed, 3 Jun 2026 11:06:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=99=AE=E9=80=9A=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E4=BA=8C=E7=BB=B4=E7=A0=81=E8=BF=9B=E5=85=A5=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- banban-mini/src/pages/bind/index.tsx | 70 +++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/banban-mini/src/pages/bind/index.tsx b/banban-mini/src/pages/bind/index.tsx index f06c1ed..b873772 100644 --- a/banban-mini/src/pages/bind/index.tsx +++ b/banban-mini/src/pages/bind/index.tsx @@ -26,6 +26,50 @@ const SESSION_STATUS_COMPLETED = 2 const SESSION_STATUS_EXPIRED = 3 const SESSION_STATUS_FAILED = 4 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 | 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 | 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 | undefined): string { + const qParam = getRouteParam(params, 'q') + return qParam ? decodeLaunchQrValue(qParam) : '' +} function normalizeExpiresAt(expiresAt: string): string { let normalized = String(expiresAt || '').trim() @@ -71,7 +115,7 @@ function parseBindingPayload(rawValue: string): { deviceId: string; serialNumber const pairMap = queryPart.split('&').reduce>((result, item) => { const [key, ...restValue] = item.split('=') if (!key) return result - result[decodeURIComponent(key)] = decodeURIComponent(restValue.join('=') || '') + result[decodeQueryComponent(key)] = decodeQueryComponent(restValue.join('=') || '') return result }, {}) const deviceId = pairMap.device_id || pairMap.deviceId || '' @@ -128,6 +172,7 @@ export default function Bind() { const [remainingBindSeconds, setRemainingBindSeconds] = useState(0) const pollingRef = useRef | null>(null) const countdownRef = useRef | null>(null) + const appliedLaunchQrRef = useRef('') useDidShow(() => { void loadPageData() @@ -200,6 +245,27 @@ export default function Bind() { 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) => { stopPolling() stopCountdown() @@ -300,6 +366,7 @@ export default function Bind() { const loadPageData = async () => { if (!getToken()) { + Taro.setStorageSync('postLoginRedirect', buildPageUrl(BIND_PAGE_URL, router.params)) Taro.reLaunch({ url: '/pages/login/index' }) return } @@ -317,6 +384,7 @@ export default function Bind() { setDeviceId(activeBinding.device_id) } else { setPendingDeviceId(null) + applyLaunchQrPayload() } } catch (error: any) { console.error('[bind] load failed:', error)