f6cd2127ae
- gamePlayClientId.ts:新增匿名游玩身份,localStorage 持久并在不可用时退化为会话内存值 - gameDistributionClient.ts:新增 recordGamePlay,携带 clientId 且按后台请求处理,不刷新会话、不改全局登录态 - GamePlayPage.tsx:点击开始游戏即 fire-and-forget 上报,失败静默不阻断进入游戏 - 补 clientId 稳定性用例与点击上报断言,并把新服务文件加入 eslint 白名单
44 lines
1.4 KiB
TypeScript
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)}`;
|
|
}
|