/** * 太阳码 / 扫码进入参数解析(冷启动 onLoad + 热启动 App.onShow 共用) */ /** 微信「扫小程序码 / 长按识别 / 相册选取」等进入场景值 */ export const SCAN_ENTRY_SCENES = [1011, 1012, 1013, 1047, 1048, 1049] /** * 解析 scene 字符串为键值对,如 s=123&a=456&id=789 */ export function parseSceneString(sceneRaw) { if (!sceneRaw) { return {} } const scene = decodeURIComponent(String(sceneRaw)) const params = {} scene.split('&').forEach((pair) => { if (!pair) { return } const eq = pair.indexOf('=') if (eq === -1) { params[pair] = '' return } const key = pair.slice(0, eq) const val = pair.slice(eq + 1) if (key) { params[key] = val != null ? decodeURI(val) : '' } }) return params } /** * 将 scene 内字段展开为页面 query(account / hdId / id 等) */ export function sceneParamsToQuery(sceneParams, baseQuery) { const q = Object.assign({}, baseQuery || {}) if (sceneParams.s) { q.account = sceneParams.s } if (sceneParams.a) { if (!q.account) { q.account = sceneParams.a } q.staffId = sceneParams.a } if (sceneParams.id) { q.id = sceneParams.id } if (sceneParams.hdId) { q.hdId = sceneParams.hdId } delete q.scene return q } /** * 合并 onLoad 的 option:scene 展开 + 普通二维码 q 参数 */ export function applyLaunchQuery(option) { const merged = Object.assign({}, option || {}) if (merged.scene) { const sceneParams = parseSceneString(merged.scene) Object.assign(merged, sceneParamsToQuery(sceneParams, merged)) delete merged.scene } if (merged.q) { const currentUrl = decodeURIComponent(String(merged.q)) const marker = 'account=' const idx = currentUrl.lastIndexOf(marker) if (idx >= 0) { let account = currentUrl.substring(idx + marker.length) const amp = account.indexOf('&') if (amp >= 0) { account = account.substring(0, amp) } merged.account = account } } return merged } /** * 拼 reLaunch 地址 */ export function buildLaunchUrl(path, query) { const normalizedPath = path && path.indexOf('/') === 0 ? path : '/' + (path || '') const parts = [] const q = query || {} Object.keys(q).forEach((key) => { const val = q[key] if (val !== undefined && val !== null && val !== '') { parts.push(key + '=' + encodeURIComponent(val)) } }) return parts.length ? normalizedPath + '?' + parts.join('&') : normalizedPath } /** * 写入 account / hdId / currentQuery(与原 globalMixins 一致) */ export function persistLaunchStorage(option) { if (option.account) { uni.setStorageSync('account', option.account) } else { uni.setStorageSync('account', 0) } if (option.hdId) { uni.setStorageSync('hdId', option.hdId) } else { uni.setStorageSync('hdId', 0) } uni.setStorageSync('currentQuery', JSON.stringify(option)) } /** 分享邀请人 customId 的 storage key(按门店隔离) */ export function getShareInviterStorageKey(account) { const shopId = account || uni.getStorageSync('account') || '' return shopId ? 'shareInviter_' + shopId : '' } /** * 缓存分享链接中的邀请人 xhCustom.id,供注册后拉新绑定 */ export function persistShareInviter(option) { const inviterCustomId = option && option.inviterCustomId ? Number(option.inviterCustomId) : 0 const account = option && option.account ? option.account : uni.getStorageSync('account') const key = getShareInviterStorageKey(account) if (!key || inviterCustomId <= 0) { return } uni.setStorageSync(key, inviterCustomId) } /** 读取当前门店缓存的邀请人 ID */ export function getShareInviterCustomId(account) { const key = getShareInviterStorageKey(account) if (!key) { return 0 } const val = uni.getStorageSync(key) return val ? Number(val) : 0 } /** 绑定成功后清除邀请人缓存 */ export function clearShareInviter(account) { const key = getShareInviterStorageKey(account) if (key) { uni.removeStorageSync(key) } } /** * 热启动:根据 getEnterOptionsSync 判断是否需要 reLaunch 到展开 query 的目标页 * @returns {boolean} 是否已触发 reLaunch */ export function tryReLaunchFromScanEnter(globalData) { if (!uni.getEnterOptionsSync) { return false } const enter = uni.getEnterOptionsSync() if (!enter || !enter.query || !enter.query.scene) { return false } const launchKey = (enter.path || '') + '|' + enter.query.scene const sceneCode = Number(enter.scene) const isScanEntry = SCAN_ENTRY_SCENES.indexOf(sceneCode) >= 0 if (!isScanEntry && globalData.lastLaunchKey === launchKey) { return false } const sceneParams = parseSceneString(enter.query.scene) const expandedQuery = sceneParamsToQuery(sceneParams, Object.assign({}, enter.query)) const targetUrl = buildLaunchUrl(enter.path, expandedQuery) const targetRoute = (enter.path || '').replace(/^\//, '') const pages = getCurrentPages() const current = pages.length ? pages[pages.length - 1] : null if (current) { const curRoute = current.route || '' const curOpts = current.options || {} // 已在目标页且参数已展开(无 scene),无需重复 reLaunch if (curRoute === targetRoute && !curOpts.scene && (curOpts.account || curOpts.id || curOpts.hdId)) { globalData.lastLaunchKey = launchKey return false } } globalData.lastLaunchKey = launchKey uni.reLaunch({ url: targetUrl }) return true }