注册必填 7-32 位账号,手机号区号/本地号分存;登录默认账号模式并支持切换手机号登录;Player i18n 拆包与赛事接口优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
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 = stripLocalPhoneDigits(localInput);
|
||
|
||
if (!dial || !local) {
|
||
throw appBadRequest('PHONE_REQUIRED');
|
||
}
|
||
if (!isSupportedPhoneDial(dial)) {
|
||
throw appBadRequest('PHONE_COUNTRY_UNSUPPORTED');
|
||
}
|
||
|
||
const combined = `${dial}${local}`;
|
||
if (combined.length < 10 || combined.length > 15) {
|
||
throw appBadRequest('PHONE_INVALID');
|
||
}
|
||
return combined;
|
||
}
|
||
|
||
/** 提取本地号码(纯数字,去掉前导 0) */
|
||
export function stripLocalPhoneDigits(localInput: string): string {
|
||
let local = localInput.replace(/\D/g, '');
|
||
if (local.startsWith('0') && local.length > 1) {
|
||
local = local.replace(/^0+/, '');
|
||
}
|
||
return local;
|
||
}
|
||
|
||
/** 玩家登录:选国家 + 本地号;字母账号(如 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()) {
|
||
const dial = countryDial.replace(/\D/g, '');
|
||
let digits = trimmed.replace(/\D/g, '');
|
||
if (digits.startsWith('0') && digits.length > 1) {
|
||
digits = digits.replace(/^0+/, '');
|
||
}
|
||
// 已输入含区号完整号码时,不再重复拼接
|
||
if (dial && digits.startsWith(dial) && digits.length >= 10) {
|
||
return digits;
|
||
}
|
||
try {
|
||
return normalizePhone(countryDial, trimmed);
|
||
} catch {
|
||
return trimmed;
|
||
}
|
||
}
|
||
|
||
const digits = trimmed.replace(/\D/g, '');
|
||
if (digits.length >= 10) return digits;
|
||
|
||
return trimmed;
|
||
}
|
||
|
||
/** 玩家登录:本地号时在开放国家中生成候选完整号码;字母账号原样返回 */
|
||
export function resolvePlayerLoginCandidates(
|
||
input: string,
|
||
countryDial?: string,
|
||
): string[] {
|
||
const trimmed = input.trim();
|
||
if (!trimmed) return [];
|
||
|
||
if (!/^[\d+\s\-()]+$/.test(trimmed)) {
|
||
return [trimmed];
|
||
}
|
||
|
||
if (countryDial?.trim()) {
|
||
return [resolvePlayerLoginUsername(input, countryDial)];
|
||
}
|
||
|
||
const digits = trimmed.replace(/\D/g, '');
|
||
if (digits.length >= 10) {
|
||
return [digits];
|
||
}
|
||
|
||
return [digits];
|
||
}
|