新增玩家头像、可查密码与全局改密/改账号开关;玩家资料页合并账号密码展示;代理直属玩家列表支持自定义上下分。 Co-authored-by: Cursor <cursoragent@cursor.com>
105 lines
4.0 KiB
TypeScript
105 lines
4.0 KiB
TypeScript
export type BuiltinPlayer = {
|
|
id: string;
|
|
name: string;
|
|
position: string;
|
|
country: string;
|
|
filename: string;
|
|
};
|
|
|
|
const BUILTIN_PLAYER_FILENAMES = [
|
|
'何塞·曼努埃尔·洛佩斯-前锋-阿根廷.jpg',
|
|
'佩德里-中场-西班牙.jpg',
|
|
'卢卡·莫德里奇-中场-克罗地亚.jpg',
|
|
'华金·皮克雷斯-中场-乌拉圭.jpg',
|
|
'乔治亚·德·阿拉斯凯塔-中场-乌拉圭.jpg',
|
|
'乌古尔坎·卡基尔-守門員-土耳其.jpg',
|
|
'亚历杭德罗·曾德哈斯-前锋-美国.jpg',
|
|
'恩德里克-前锋-巴西.jpg',
|
|
'克里斯蒂亚诺·罗纳尔多-前锋-葡萄牙.jpg',
|
|
'克里斯蒂安·罗梅罗-后卫-阿根廷.jpg',
|
|
'内马尔-前锋-巴西.jpg',
|
|
'凯南·耶尔德兹-前锋-土耳其.jpg',
|
|
'卡塞米罗-中场-巴西.jpg',
|
|
'卢卡斯·帕奎塔-中场-巴西.jpg',
|
|
'基利安·姆巴佩-前锋-法国.jpg',
|
|
'孟菲斯·德派-前锋-荷兰.jpg',
|
|
'奥斯曼·登贝莱-前锋-法国.jpg',
|
|
'布鲁诺·吉马良斯-中场-巴西.jpg',
|
|
'布鲁诺·费尔南德斯-中场-葡萄牙.jpg',
|
|
'布卡约·萨卡-前锋-英格兰.jpg',
|
|
'德尼兹·居尔-前锋-土耳其.jpg',
|
|
'德尼兹·温达夫-前锋-德国.jpg',
|
|
'拉斐尔·迪亚斯·贝洛利-前锋-巴西.jpg',
|
|
'拉明·亚马尔-前锋-西班牙.jpg',
|
|
'朱利安·阿尔瓦雷斯-前锋-阿根廷.jpg',
|
|
'梅西-前锋-阿根廷.jpg',
|
|
'迈克尔·奥利塞-前锋-法国.jpg',
|
|
'穆罕默德·萨拉赫-前锋-埃及.jpg',
|
|
'维尼修斯·儒尼奥尔-前锋-巴西.jpg',
|
|
'维克托·哲凯赖什-前锋-瑞典.jpg',
|
|
'圣地亚哥·吉梅内斯-前锋-墨西哥.jpg',
|
|
'埃德森·阿尔瓦雷斯-后卫-墨西哥.jpg',
|
|
'埃贝雷奇·埃泽-中场-英格兰.jpg',
|
|
'埃尔林·哈兰德-前锋-挪威.jpg',
|
|
'蒂博·库尔图瓦-守門員-比利时.jpg',
|
|
'曼努埃尔·诺伊尔-守門員-德国.jpg',
|
|
'祖德·贝林厄姆-中场-英格兰.jpg',
|
|
'伦纳特·卡尔-中场-德国.jpg',
|
|
'费德里科·巴尔韦德-中场-乌拉圭.jpg',
|
|
'贾马尔·慕斯拉-中场-德国.jpg',
|
|
'路易斯·迪亚斯-前锋-哥伦比亚.jpg',
|
|
'阿什拉夫·哈基米-后卫-摩洛哥.jpg',
|
|
'阿利松·贝克尔-守門員-巴西.jpg',
|
|
'阿尔达·居莱尔-前锋-土耳其.jpg',
|
|
'马西斯·拉扬·切尔基-中场-法国.jpg',
|
|
'马库斯·拉什福德-前锋-英格兰.jpg',
|
|
'哈里·凯恩-前锋-英格兰.jpg',
|
|
'尼科·威廉斯-前锋-西班牙.jpg',
|
|
'巴勃罗·加维-中场-西班牙.jpg',
|
|
'吉列尔莫·奥乔亚-守門員-墨西哥.jpg',
|
|
] as const;
|
|
|
|
function parsePlayerFilename(filename: string): BuiltinPlayer {
|
|
const base = filename.replace(/\.jpg$/i, '');
|
|
const parts = base.split('-');
|
|
const country = parts.pop() ?? '';
|
|
const position = parts.pop() ?? '';
|
|
const name = parts.join('-');
|
|
return { id: base, name, position, country, filename };
|
|
}
|
|
|
|
export const BUILTIN_PLAYERS: BuiltinPlayer[] = BUILTIN_PLAYER_FILENAMES.map(parsePlayerFilename);
|
|
|
|
const AVATAR_KEY_SET = new Set(BUILTIN_PLAYERS.map((p) => p.id));
|
|
|
|
export function isValidAvatarKey(key: string | null | undefined): boolean {
|
|
if (!key) return true;
|
|
return AVATAR_KEY_SET.has(key);
|
|
}
|
|
|
|
export function playerAvatarUrl(key: string | null | undefined): string | null {
|
|
if (!key) return null;
|
|
const player = BUILTIN_PLAYERS.find((p) => p.id === key);
|
|
if (!player) return null;
|
|
return `/球员/${player.filename}`;
|
|
}
|
|
|
|
export function getBuiltinPlayer(key: string | null | undefined): BuiltinPlayer | null {
|
|
if (!key) return null;
|
|
return BUILTIN_PLAYERS.find((p) => p.id === key) ?? null;
|
|
}
|
|
|
|
/** 按 seed 稳定随机,无 seed 时完全随机 */
|
|
export function randomAvatarKey(seed?: string | number | null): string {
|
|
if (!BUILTIN_PLAYERS.length) return '';
|
|
if (seed === undefined || seed === null || seed === '') {
|
|
return BUILTIN_PLAYERS[Math.floor(Math.random() * BUILTIN_PLAYERS.length)].id;
|
|
}
|
|
const text = String(seed);
|
|
let hash = 0;
|
|
for (let i = 0; i < text.length; i += 1) {
|
|
hash = (hash * 31 + text.charCodeAt(i)) >>> 0;
|
|
}
|
|
return BUILTIN_PLAYERS[hash % BUILTIN_PLAYERS.length].id;
|
|
}
|