Files
Genarrative/src/services/gamePlayClientId.ts
T
k88936 f6cd2127ae 前端:点击开始游戏上报游玩次数
- gamePlayClientId.ts:新增匿名游玩身份,localStorage 持久并在不可用时退化为会话内存值
- gameDistributionClient.ts:新增 recordGamePlay,携带 clientId 且按后台请求处理,不刷新会话、不改全局登录态
- GamePlayPage.tsx:点击开始游戏即 fire-and-forget 上报,失败静默不阻断进入游戏
- 补 clientId 稳定性用例与点击上报断言,并把新服务文件加入 eslint 白名单
2026-10-03 18:25:49 +08:00

44 lines
1.4 KiB
TypeScript

/**
* 匿名游玩身份。
*
* 登录用户由后端从 bearer 取 `userId`,匿名用户只能靠前端持久一个随机 `clientId`。这里把
* 生成、读取与降级收在一个小模块里:`localStorage` 不可用(隐私模式、SSR、被禁用)时退化为
* 当前会话内存值,保证一次会话内多次点击仍去重。
*/
const GAME_PLAY_CLIENT_ID_STORAGE_KEY = 'genarrative.game-play.client-id.v1';
let cachedClientId: string | null = null;
/** 返回稳定的匿名游玩身份;同一标签页内重复调用返回同一个值。 */
export function getGamePlayClientId(): string {
if (cachedClientId) return cachedClientId;
try {
const stored = window.localStorage
.getItem(GAME_PLAY_CLIENT_ID_STORAGE_KEY)
?.trim();
if (stored) {
cachedClientId = stored;
return stored;
}
const created = createGamePlayClientId();
window.localStorage.setItem(GAME_PLAY_CLIENT_ID_STORAGE_KEY, created);
cachedClientId = created;
return created;
} catch {
cachedClientId = cachedClientId ?? createGamePlayClientId();
return cachedClientId;
}
}
function createGamePlayClientId(): string {
if (
typeof crypto !== 'undefined' &&
typeof crypto.randomUUID === 'function'
) {
return crypto.randomUUID();
}
return `gp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
}