Files
sub2api/frontend/src/utils/oauthAffiliate.ts
shaw 9b6dcc57bd feat(affiliate): 完善邀请返利系统
- 修复返利不到账的根因:tryClaimAffiliateRebateAudit 中 PostgreSQL 参数类型推断冲突
  - 补全 OAuth 注册路径(LinuxDo/OIDC/WeChat/Pending Flow)的邀请码绑定
  - 前端 OAuth 注册页面传递 aff_code 参数
  - 新增返利冻结期机制:可配置冻结时间,到期后自动解冻(懒解冻)
  - 新增返利有效期:绑定后 N 天内有效,过期不再产生返利
  - 新增单人返利上限:超出上限部分精确截断
  - 增强返利流程 slog 结构化日志,便于排查问题
  - 已邀请用户列表增加返利明细列
2026-04-26 12:42:35 +08:00

134 lines
3.3 KiB
TypeScript

const OAUTH_AFFILIATE_CODE_KEY = 'oauth_aff_code'
const AFFILIATE_REFERRAL_CODE_KEY = 'affiliate_referral_code'
const AFFILIATE_REFERRAL_TTL_MS = 30 * 24 * 60 * 60 * 1000
interface StoredAffiliateReferralCode {
code: string
expiresAt: number
}
export function normalizeOAuthAffiliateCode(value?: unknown): string {
const raw = Array.isArray(value) ? value[0] : value
return typeof raw === 'string' ? raw.trim() : ''
}
export function pickOAuthAffiliateCode(...values: unknown[]): string {
for (const value of values) {
const code = normalizeOAuthAffiliateCode(value)
if (code) {
return code
}
}
return ''
}
export function storeAffiliateReferralCode(value?: unknown, now = Date.now()): void {
if (typeof window === 'undefined') {
return
}
const code = normalizeOAuthAffiliateCode(value)
if (!code) {
return
}
try {
const payload: StoredAffiliateReferralCode = {
code,
expiresAt: now + AFFILIATE_REFERRAL_TTL_MS
}
window.localStorage.setItem(AFFILIATE_REFERRAL_CODE_KEY, JSON.stringify(payload))
} catch {
// 忽略浏览器存储异常。
}
}
export function loadAffiliateReferralCode(now = Date.now()): string {
if (typeof window === 'undefined') {
return ''
}
try {
const raw = window.localStorage.getItem(AFFILIATE_REFERRAL_CODE_KEY)
if (!raw) {
return ''
}
const parsed = JSON.parse(raw) as Partial<StoredAffiliateReferralCode>
const code = normalizeOAuthAffiliateCode(parsed.code)
const expiresAt = Number(parsed.expiresAt) || 0
if (!code || expiresAt <= now) {
clearAffiliateReferralCode()
return ''
}
return code
} catch {
clearAffiliateReferralCode()
return ''
}
}
export function clearAffiliateReferralCode(): void {
if (typeof window === 'undefined') {
return
}
try {
window.localStorage.removeItem(AFFILIATE_REFERRAL_CODE_KEY)
} catch {
// 忽略浏览器存储异常。
}
}
export function resolveAffiliateReferralCode(...values: unknown[]): string {
const code = pickOAuthAffiliateCode(...values)
if (code) {
storeAffiliateReferralCode(code)
return code
}
return loadAffiliateReferralCode()
}
export function storeOAuthAffiliateCode(value?: unknown): void {
if (typeof window === 'undefined') {
return
}
const code = normalizeOAuthAffiliateCode(value)
try {
if (code) {
window.sessionStorage.setItem(OAUTH_AFFILIATE_CODE_KEY, code)
} else {
window.sessionStorage.removeItem(OAUTH_AFFILIATE_CODE_KEY)
}
} catch {
// 忽略浏览器存储异常。
}
}
export function loadOAuthAffiliateCode(): string {
if (typeof window === 'undefined') {
return ''
}
try {
return normalizeOAuthAffiliateCode(window.sessionStorage.getItem(OAUTH_AFFILIATE_CODE_KEY))
} catch {
return ''
}
}
export function clearOAuthAffiliateCode(): void {
if (typeof window === 'undefined') {
return
}
try {
window.sessionStorage.removeItem(OAUTH_AFFILIATE_CODE_KEY)
} catch {
// 忽略浏览器存储异常。
}
}
export function clearAllAffiliateReferralCodes(): void {
clearOAuthAffiliateCode()
clearAffiliateReferralCode()
}
export function oauthAffiliatePayload(value?: unknown): { aff_code?: string } {
const code = normalizeOAuthAffiliateCode(value)
return code ? { aff_code: code } : {}
}