import Taro from '@tarojs/taro'; import { request } from './api'; const PROMO_ID_KEY = 'dukang_promo_id'; /** 同一次进入只 touch 一次扫码计数,避免首页反复 onShow 刷量 */ let lastScanTouchKey = ''; function safeDecode(raw: string): string { try { return decodeURIComponent(raw); } catch { return raw; } } function normalizePromoId(raw: unknown): string | null { if (raw == null || raw === '') return null; const s = safeDecode(String(raw)).trim(); // 小程序码 scene 写入的是推广活动数字 ID if (!/^\d+$/.test(s)) return null; return s; } type EnterOptionsLike = { scene?: string | number; query?: Record; path?: string; }; /** 从启动/进入参数解析推广活动 ID(优先 query.scene,与 getwxacodeunlimit 一致) */ export function extractPromoIdFromEnterOptions(opts?: EnterOptionsLike | null): string | null { if (!opts) return null; const q = opts.query ?? {}; return ( normalizePromoId(q.scene) || normalizePromoId(q.promoId) || normalizePromoId(q.pid) || null ); } export function getStoredPromoId(): string | null { try { const v = Taro.getStorageSync(PROMO_ID_KEY); return normalizePromoId(v); } catch { return null; } } export function setStoredPromoId(promoId: string) { const id = normalizePromoId(promoId); if (!id) return; try { Taro.setStorageSync(PROMO_ID_KEY, id); } catch { /* ignore */ } } function readEnterOptions(): EnterOptionsLike | null { try { if (typeof Taro.getEnterOptionsSync === 'function') { return Taro.getEnterOptionsSync() as EnterOptionsLike; } } catch { /* ignore */ } try { if (typeof Taro.getLaunchOptionsSync === 'function') { return Taro.getLaunchOptionsSync() as EnterOptionsLike; } } catch { /* ignore */ } // H5:从 URL query 读取 if (process.env.TARO_ENV === 'h5' && typeof window !== 'undefined') { const params = new URLSearchParams(window.location.search); return { query: { scene: params.get('scene') || undefined, promoId: params.get('promoId') || undefined, pid: params.get('pid') || undefined, }, }; } return null; } /** * 主页面进入时:取出 scene(活动 ID)本地缓存,并回传 /promo/touch 累加扫码次数。 * 同一进入会话只计一次扫码。 */ export async function capturePromoSceneAndTouchScan(): Promise { const opts = readEnterOptions(); const fromEnter = extractPromoIdFromEnterOptions(opts); if (fromEnter) { setStoredPromoId(fromEnter); const touchKey = `${fromEnter}|${opts?.path || ''}|${JSON.stringify(opts?.query || {})}|${String(opts?.scene ?? '')}`; if (touchKey === lastScanTouchKey) return; lastScanTouchKey = touchKey; await touchPromo({ promoId: fromEnter, countScan: true }); return; } // 无新 scene 时不重复扫码计数 } /** 登录成功后:用已缓存的活动 ID 做归因(不重复加扫码次数) */ export async function touchStoredPromoAfterLogin(): Promise { const promoId = getStoredPromoId(); if (!promoId) return; await touchPromo({ promoId, countScan: false }); } async function touchPromo(input: { promoId: string; countScan: boolean }): Promise { try { await request('/promo/touch', { method: 'POST', data: { promoId: input.promoId, countScan: input.countScan, }, }); } catch { /* 静默失败,不阻断浏览 */ } }