const INVITE_MAX_AGE = 30 * 24 * 3600 function normalizeInviteCode(value) { const text = Array.isArray(value) ? value[0] : value const code = String(text || '').trim() return /^[a-zA-Z0-9_-]{1,64}$/.test(code) ? code : '' } function parseInviteScene(value) { if (!value) return '' let text = String(Array.isArray(value) ? value[0] : value) try { text = decodeURIComponent(text) } catch { // 保留原始 scene,交给后续格式校验。 } const match = text.match(/(?:^|[&?])i=([^&]+)/) || text.match(/(?:^|[&?])i_([^&]+)/) if (match) return normalizeInviteCode(match[1]) if (text.startsWith('i_')) return normalizeInviteCode(text.slice(2)) return '' } export function useInvite() { const inviteCode = useCookie('invite_code', { maxAge: INVITE_MAX_AGE, path: '/', sameSite: 'lax', }) const source = useCookie('source', { maxAge: INVITE_MAX_AGE, path: '/', sameSite: 'lax', }) const runtimeConfig = useRuntimeConfig() const requestUrl = useRequestURL() function captureInvite(query = {}) { const token = useCookie('token', { path: '/' }) const code = normalizeInviteCode(query.invite_code) || normalizeInviteCode(query.invite_open_id) || parseInviteScene(query.scene) // 已登录用户不会再触发注册奖励,避免在共享设备上污染下一位登录用户。 if (code && !token.value) inviteCode.value = code const sourceValue = String(Array.isArray(query.source) ? query.source[0] : query.source || '').trim() if (sourceValue && sourceValue.length <= 50) source.value = sourceValue return code } function withInvite(params = {}) { const code = normalizeInviteCode(inviteCode.value) return code ? { ...params, invite_open_id: code } : { ...params } } function clearInvite() { inviteCode.value = null } function buildInvitePath(code) { const normalized = normalizeInviteCode(code) if (!normalized) return '/invite/landing' const query = new URLSearchParams({ invite_code: normalized, source: 'pc_invite', }) return `/invite/landing?${query.toString()}` } function buildInviteUrl(code) { const configuredOrigin = String(runtimeConfig.public.siteUrl || '').replace(/\/+$/, '') const origin = configuredOrigin || requestUrl.origin return `${origin}${buildInvitePath(code)}` } return { inviteCode, source, captureInvite, withInvite, clearInvite, buildInvitePath, buildInviteUrl, normalizeInviteCode, } }