feat(player): 接入创蓝短信手机注册与登录页优化

新增 SMS 验证码注册、8 国手机号选择与 Redis 频控;优化登录/注册 UI 及图形验证码样式。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-12 10:25:59 +08:00
parent 168aecfd5c
commit db28390be9
39 changed files with 1521 additions and 107 deletions

View File

@@ -0,0 +1,52 @@
import { appBadRequest } from '../../../shared/common/app-error';
import { isSupportedPhoneDial } from '@thebet365/shared';
/** 归一化为创蓝格式:国家区号 + 本地号码(纯数字,无 + */
export function normalizePhone(countryDial: string, localInput: string): string {
const dial = countryDial.replace(/\D/g, '');
let local = localInput.replace(/\D/g, '');
if (!dial || !local) {
throw appBadRequest('PHONE_REQUIRED');
}
if (!isSupportedPhoneDial(dial)) {
throw appBadRequest('PHONE_COUNTRY_UNSUPPORTED');
}
// 马来西亚等本地号常以 0 开头
if (local.startsWith('0') && local.length > 1) {
local = local.replace(/^0+/, '');
}
const combined = `${dial}${local}`;
if (combined.length < 10 || combined.length > 15) {
throw appBadRequest('PHONE_INVALID');
}
return combined;
}
/** 玩家登录:选国家 + 本地号;字母账号(如 player1原样返回 */
export function resolvePlayerLoginUsername(
input: string,
countryDial?: string,
): string {
const trimmed = input.trim();
if (!trimmed) return trimmed;
if (!/^[\d+\s\-()]+$/.test(trimmed)) {
return trimmed;
}
if (countryDial?.trim()) {
try {
return normalizePhone(countryDial, trimmed);
} catch {
return trimmed;
}
}
const digits = trimmed.replace(/\D/g, '');
if (digits.length >= 10) return digits;
return trimmed;
}