import { FormValidationError } from '../i18n/form-validation'; /** 玩家用户名:仅英文字母与数字,3–32 位 */ export const PLAYER_USERNAME_PATTERN = /^[a-zA-Z0-9]{3,32}$/; export function assertPlayerUsername(username: string): void { const trimmed = username.trim(); if (!trimmed) throw new FormValidationError('err.username_required'); if (!PLAYER_USERNAME_PATTERN.test(trimmed)) { throw new FormValidationError('err.username_player_invalid'); } } export interface PlayerCreateForm { username: string; password: string; confirmPassword: string; parentId: string; phone: string; email: string; initialDeposit: number; remark: string; /** 创建为一级代理(非玩家) */ asTier1Agent: boolean; creditLimit: number; cashbackRate: number; maxSingleDeposit: number; maxDailyDeposit: number; } export interface PlayerEditForm { id: string; username: string; status: string; parentUsername: string | null; affiliationAgents?: string[]; availableBalance: string; frozenBalance: string; betCount: number; totalStake: string; totalReturn: string; createdAt: string; lastLoginAt: string | null; loginFailCount: number; phone: string; email: string; managedPassword: string | null; newPassword: string; } export interface PlayerRow { id: string; username: string; status: string; locale: string; parentId: string | null; parentUsername: string | null; /** 归属代理链:一级代理、二级代理(如有) */ affiliationAgents?: string[]; phone: string | null; email: string | null; managedPassword: string | null; availableBalance: string; frozenBalance: string; lastLoginAt: string | null; betCount: number; totalStake: string; totalReturn: string; createdAt: string; } export interface PlayerDetail extends PlayerRow { loginFailCount: number; lockedUntil: string | null; updatedAt: string; } /** 玩家归属标签,格式:玩家-平台 | 玩家-一级代理 | 玩家-一级代理-二级代理 */ export function formatPlayerAffiliationLabel( row: Pick, playerLabel: string, platformLabel: string, ): string { const agents = row.affiliationAgents ?? []; if (agents.length === 0) { return [playerLabel, platformLabel].join('-'); } return [playerLabel, ...agents].join('-'); } export function emptyPlayerCreateForm(): PlayerCreateForm { return { username: '', password: '', confirmPassword: '', parentId: '', phone: '', email: '', initialDeposit: 0, remark: '', asTier1Agent: false, creditLimit: 50000, cashbackRate: 0, maxSingleDeposit: 0, maxDailyDeposit: 0, }; } export function emptyPlayerEditForm(): PlayerEditForm { return { id: '', username: '', status: 'ACTIVE', parentUsername: null, availableBalance: '0', frozenBalance: '0', betCount: 0, totalStake: '0', totalReturn: '0', createdAt: '', lastLoginAt: null, loginFailCount: 0, phone: '', email: '', managedPassword: null, newPassword: '', }; } export function editFormFromDetail(d: PlayerDetail): PlayerEditForm { return { id: d.id, username: d.username, status: d.status, parentUsername: d.parentUsername, affiliationAgents: d.affiliationAgents, availableBalance: d.availableBalance, frozenBalance: d.frozenBalance, betCount: d.betCount, totalStake: d.totalStake, totalReturn: d.totalReturn, createdAt: d.createdAt, lastLoginAt: d.lastLoginAt, loginFailCount: d.loginFailCount, phone: d.phone ?? '', email: d.email ?? '', managedPassword: d.managedPassword ?? null, newPassword: '', }; } export function buildCreatePlayerPayload(form: PlayerCreateForm) { if (!form.username.trim()) throw new FormValidationError('err.username_required'); if (form.password.length < 8) throw new FormValidationError('err.password_min'); if (form.password !== form.confirmPassword) throw new FormValidationError('err.password_mismatch'); if (form.asTier1Agent) { if (form.parentId) throw new FormValidationError('err.agent_no_parent'); if (form.initialDeposit > 0) throw new FormValidationError('err.agent_no_initial_deposit'); if (form.creditLimit < 0) throw new FormValidationError('err.credit_negative'); return { username: form.username.trim(), password: form.password, phone: form.phone.trim() || undefined, email: form.email.trim() || undefined, asTier1Agent: true, creditLimit: form.creditLimit, cashbackRate: form.cashbackRate, maxSingleDeposit: form.maxSingleDeposit > 0 ? form.maxSingleDeposit : undefined, maxDailyDeposit: form.maxDailyDeposit > 0 ? form.maxDailyDeposit : undefined, }; } assertPlayerUsername(form.username); return { username: form.username.trim(), password: form.password, parentId: form.parentId || undefined, phone: form.phone.trim() || undefined, email: form.email.trim() || undefined, initialDeposit: form.initialDeposit > 0 ? form.initialDeposit : undefined, remark: form.remark.trim() || undefined, }; }