feat(affiliate): 完善邀请返利系统

- 修复返利不到账的根因:tryClaimAffiliateRebateAudit 中 PostgreSQL 参数类型推断冲突
  - 补全 OAuth 注册路径(LinuxDo/OIDC/WeChat/Pending Flow)的邀请码绑定
  - 前端 OAuth 注册页面传递 aff_code 参数
  - 新增返利冻结期机制:可配置冻结时间,到期后自动解冻(懒解冻)
  - 新增返利有效期:绑定后 N 天内有效,过期不再产生返利
  - 新增单人返利上限:超出上限部分精确截断
  - 增强返利流程 slog 结构化日志,便于排查问题
  - 已邀请用户列表增加返利明细列
This commit is contained in:
shaw
2026-04-26 12:31:52 +08:00
parent 496469ac4e
commit 9b6dcc57bd
42 changed files with 852 additions and 104 deletions

View File

@@ -564,9 +564,10 @@ export async function resetPassword(request: ResetPasswordRequest): Promise<Rese
*/
export async function completeLinuxDoOAuthRegistration(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<OAuthTokenResponse> {
return createPendingLinuxDoOAuthAccount(invitationCode, decision)
return createPendingLinuxDoOAuthAccount(invitationCode, decision, affiliateCode)
}
/**
@@ -576,27 +577,32 @@ export async function completeLinuxDoOAuthRegistration(
*/
export async function completeOIDCOAuthRegistration(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<OAuthTokenResponse> {
return createPendingOIDCOAuthAccount(invitationCode, decision)
return createPendingOIDCOAuthAccount(invitationCode, decision, affiliateCode)
}
export async function completeWeChatOAuthRegistration(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<OAuthTokenResponse> {
return createPendingWeChatOAuthAccount(invitationCode, decision)
return createPendingWeChatOAuthAccount(invitationCode, decision, affiliateCode)
}
async function createPendingOAuthAccount(
provider: 'linuxdo' | 'oidc' | 'wechat',
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<PendingOAuthCreateAccountResponse> {
const normalizedAffiliateCode = affiliateCode?.trim()
const { data } = await apiClient.post<PendingOAuthCreateAccountResponse>(
`/auth/oauth/${provider}/complete-registration`,
{
invitation_code: invitationCode,
...(normalizedAffiliateCode ? { aff_code: normalizedAffiliateCode } : {}),
...serializeOAuthAdoptionDecision(decision)
}
)
@@ -605,23 +611,26 @@ async function createPendingOAuthAccount(
export async function createPendingLinuxDoOAuthAccount(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<PendingOAuthCreateAccountResponse> {
return createPendingOAuthAccount('linuxdo', invitationCode, decision)
return createPendingOAuthAccount('linuxdo', invitationCode, decision, affiliateCode)
}
export async function createPendingOIDCOAuthAccount(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<PendingOAuthCreateAccountResponse> {
return createPendingOAuthAccount('oidc', invitationCode, decision)
return createPendingOAuthAccount('oidc', invitationCode, decision, affiliateCode)
}
export async function createPendingWeChatOAuthAccount(
invitationCode: string,
decision?: OAuthAdoptionDecision
decision?: OAuthAdoptionDecision,
affiliateCode?: string
): Promise<PendingOAuthCreateAccountResponse> {
return createPendingOAuthAccount('wechat', invitationCode, decision)
return createPendingOAuthAccount('wechat', invitationCode, decision, affiliateCode)
}
export async function completePendingOAuthBindLogin(