代下单功能

This commit is contained in:
2026-07-12 11:40:04 +08:00
parent d949301bc1
commit de01d36cdb
46 changed files with 2657 additions and 253 deletions
+1 -2
View File
@@ -20,13 +20,12 @@ import RedeemSuccessPage from './pages/RedeemSuccessPage';
import PayPage from './pages/PayPage';
import CustomerServicePage from './pages/CustomerServicePage';
import { UserSessionProvider } from './contexts/UserSessionContext';
import { capturePromoFromUrl, touchPromoIfNeeded } from './lib/promo';
import { capturePromoFromUrl } from './lib/promo';
import WechatShareBootstrap from './components/WechatShareBootstrap';
function PromoBootstrap() {
useEffect(() => {
capturePromoFromUrl();
void touchPromoIfNeeded();
}, []);
return null;
}
+28 -11
View File
@@ -1,25 +1,33 @@
import { apiBase } from './api';
export const PROMO_STORAGE_KEY = 'dukang_promo_code';
export const PROMO_PID_STORAGE_KEY = 'dukang_promo_pid';
function readPromoFromSearch(search: string): string | null {
function readPromoFromSearch(search: string): { code: string | null; pid: string | null } {
const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
const code = params.get('promo')?.trim();
return code ? code.toUpperCase() : null;
const pid = params.get('pid')?.trim();
return {
code: code ? code.toUpperCase() : null,
pid: pid || null,
};
}
/** 解析 URL 中的 ?promo= 并写入 sessionStorage */
/** 解析 URL 中的 ?promo= / ?pid= 并写入 sessionStorage */
export function capturePromoFromUrl(): string | null {
if (typeof window === 'undefined') return null;
let code = readPromoFromSearch(window.location.search);
if (!code && window.location.hash.includes('?')) {
let parsed = readPromoFromSearch(window.location.search);
if (!parsed.code && !parsed.pid && window.location.hash.includes('?')) {
const hashQuery = window.location.hash.slice(window.location.hash.indexOf('?'));
code = readPromoFromSearch(hashQuery);
parsed = readPromoFromSearch(hashQuery);
}
if (code) {
sessionStorage.setItem(PROMO_STORAGE_KEY, code);
if (parsed.code) {
sessionStorage.setItem(PROMO_STORAGE_KEY, parsed.code);
}
return code ?? sessionStorage.getItem(PROMO_STORAGE_KEY);
if (parsed.pid) {
sessionStorage.setItem(PROMO_PID_STORAGE_KEY, parsed.pid);
}
return parsed.code ?? sessionStorage.getItem(PROMO_STORAGE_KEY);
}
export function getStoredPromoCode(): string | null {
@@ -27,10 +35,16 @@ export function getStoredPromoCode(): string | null {
return sessionStorage.getItem(PROMO_STORAGE_KEY);
}
export function getStoredPromoPid(): string | null {
if (typeof window === 'undefined') return null;
return sessionStorage.getItem(PROMO_PID_STORAGE_KEY);
}
/** 调用 /promo/touch 完成扫码归因(OptionalJwt:未登录也累加 scan_count */
export async function touchPromoIfNeeded(): Promise<void> {
const promoCode = getStoredPromoCode();
if (!promoCode) return;
const qrcodeId = getStoredPromoPid();
if (!promoCode && !qrcodeId) return;
const headers: Record<string, string> = {
'Content-Type': 'application/json',
@@ -43,7 +57,10 @@ export async function touchPromoIfNeeded(): Promise<void> {
const res = await fetch(`${apiBase}/promo/touch`, {
method: 'POST',
headers,
body: JSON.stringify({ promoCode }),
body: JSON.stringify({
...(promoCode ? { promoCode } : {}),
...(qrcodeId ? { qrcodeId } : {}),
}),
});
const json = await res.json();
if (json.code !== 0) return;