Merge commit 'fcf1d45522e3ba6e6faf2590b60f2db1ef90e73c' into dev_jacy

This commit is contained in:
2026-07-07 13:55:10 +08:00
85 changed files with 11210 additions and 164 deletions
+53
View File
@@ -0,0 +1,53 @@
import { apiBase } from './api';
export const PROMO_STORAGE_KEY = 'dukang_promo_code';
function readPromoFromSearch(search: string): string | null {
const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
const code = params.get('promo')?.trim();
return code ? code.toUpperCase() : null;
}
/** 解析 URL 中的 ?promo= 并写入 sessionStorage */
export function capturePromoFromUrl(): string | null {
if (typeof window === 'undefined') return null;
let code = readPromoFromSearch(window.location.search);
if (!code && window.location.hash.includes('?')) {
const hashQuery = window.location.hash.slice(window.location.hash.indexOf('?'));
code = readPromoFromSearch(hashQuery);
}
if (code) {
sessionStorage.setItem(PROMO_STORAGE_KEY, code);
}
return code ?? sessionStorage.getItem(PROMO_STORAGE_KEY);
}
export function getStoredPromoCode(): string | null {
if (typeof window === 'undefined') return null;
return sessionStorage.getItem(PROMO_STORAGE_KEY);
}
/** 调用 /promo/touch 完成扫码归因(OptionalJwt:未登录也累加 scan_count */
export async function touchPromoIfNeeded(): Promise<void> {
const promoCode = getStoredPromoCode();
if (!promoCode) return;
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'X-Client-App': 'USER_H5',
};
const token = localStorage.getItem('accessToken');
if (token) headers.Authorization = `Bearer ${token}`;
try {
const res = await fetch(`${apiBase}/promo/touch`, {
method: 'POST',
headers,
body: JSON.stringify({ promoCode }),
});
const json = await res.json();
if (json.code !== 0) return;
} catch {
/* 静默失败,不阻断用户流程 */
}
}