2025-11-12 00:13:26 +08:00
|
|
|
|
import { useEffect, useState, useMemo, useCallback } from 'react';
|
2025-11-11 18:48:54 +08:00
|
|
|
|
import useGameStore from '@/stores/gameStore';
|
|
|
|
|
|
import { GameMainTypesEnum, defaultHomeGameTabMenus, gameMainTypesMap } from '@/constants/game';
|
|
|
|
|
|
import { ThemeEnum } from '@/constants/theme';
|
|
|
|
|
|
import { forEach, cloneDeep, map, filter } from 'lodash-es';
|
|
|
|
|
|
import { useIsLoggedIn } from '@/stores/userStore';
|
2025-11-13 16:47:10 +08:00
|
|
|
|
// import { useShallow } from 'zustand/react/shallow';
|
2025-11-12 00:13:26 +08:00
|
|
|
|
import storageManager, { STORAGE_KEYS } from '@/utils/storageManager';
|
|
|
|
|
|
|
|
|
|
|
|
type GameMenu = {
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
key: string;
|
|
|
|
|
|
icon?: string;
|
|
|
|
|
|
logo?: string;
|
|
|
|
|
|
children?: GameMenu[];
|
|
|
|
|
|
};
|
2025-11-11 18:48:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 有子菜单的游戏类型
|
|
|
|
|
|
const hasSubGameMainTypes = [
|
|
|
|
|
|
GameMainTypesEnum.CHESS,
|
|
|
|
|
|
GameMainTypesEnum.ELECTRONIC,
|
|
|
|
|
|
GameMainTypesEnum.FISHING,
|
|
|
|
|
|
GameMainTypesEnum.BLOCK_THIRD,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
export const useGameMainMenus = (theme: ThemeEnum) => {
|
|
|
|
|
|
// 在 hook 顶层调用 useIsLoggedIn
|
|
|
|
|
|
const isLogin = useIsLoggedIn();
|
|
|
|
|
|
|
|
|
|
|
|
// 从 store 获取必要的数据 - 直接获取,不使用 useShallow
|
|
|
|
|
|
const menuSort = useGameStore((state) => state.menuSort);
|
|
|
|
|
|
const gameBigClass = useGameStore((state) => state.gameBigClass);
|
|
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
|
console.log('🎮 useGameMainMenus - menuSort:', menuSort, 'length:', menuSort?.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 使用 useMemo 缓存计算结果,避免每次都创建新对象
|
|
|
|
|
|
return useMemo(() => {
|
|
|
|
|
|
const defaultMenus = cloneDeep(defaultHomeGameTabMenus);
|
|
|
|
|
|
|
|
|
|
|
|
if (theme === ThemeEnum.DARK) {
|
|
|
|
|
|
forEach(defaultMenus, (item) => {
|
|
|
|
|
|
if (item.key === GameMainTypesEnum.RECENT) {
|
|
|
|
|
|
item.icon = 'clock-solid_dark';
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const gameMenu = map(menuSort, (item: Record<string, any>) => {
|
|
|
|
|
|
const typeName = gameMainTypesMap[item.type as GameMainTypesEnum];
|
|
|
|
|
|
|
|
|
|
|
|
const children = hasSubGameMainTypes.includes(item.type)
|
2025-11-13 16:47:10 +08:00
|
|
|
|
? map(
|
|
|
|
|
|
gameBigClass?.[typeName].sort((a: any, b: any) => a.play_sort - b.play_sort),
|
|
|
|
|
|
(it) => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
name: it.play_cname,
|
|
|
|
|
|
key: `${it.play_id}`,
|
|
|
|
|
|
play_sort: it.play_sort,
|
|
|
|
|
|
darkImgSrc: `/images/game/${typeName}/dark_${it.play_id}.png`,
|
|
|
|
|
|
lightImgSrc: `/images/game/${typeName}/light_${it.play_id}.png`,
|
|
|
|
|
|
colorImgSrc: it.logo3_img_url || `/images/game/${typeName}/color_${it.play_id}.png`,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
2025-11-11 18:48:54 +08:00
|
|
|
|
: [];
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
name: item.play_name,
|
|
|
|
|
|
key: `${item.type}`,
|
|
|
|
|
|
icon: typeName,
|
|
|
|
|
|
logo: item.logo_url1,
|
|
|
|
|
|
children,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
|
console.log(gameMenu, 'gameMenu');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return map(
|
|
|
|
|
|
[
|
|
|
|
|
|
...filter(defaultMenus, (item) => [GameMainTypesEnum.RECOMMEND].includes(item.key)),
|
|
|
|
|
|
...(isLogin
|
|
|
|
|
|
? filter(gameMenu, (item) => Number(item.key) !== GameMainTypesEnum.TRIAL)
|
|
|
|
|
|
: gameMenu),
|
|
|
|
|
|
...filter(defaultMenus, (item) =>
|
|
|
|
|
|
[GameMainTypesEnum.COLLECT, GameMainTypesEnum.RECENT].includes(item.key)
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
(item) => ({
|
|
|
|
|
|
...item,
|
2025-11-12 00:13:26 +08:00
|
|
|
|
icon: item.icon,
|
2025-11-11 18:48:54 +08:00
|
|
|
|
key: `${item.key}`,
|
|
|
|
|
|
})
|
2025-11-12 00:13:26 +08:00
|
|
|
|
) as GameMenu[];
|
2025-11-11 18:48:54 +08:00
|
|
|
|
}, [theme, isLogin, menuSort, gameBigClass]);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const useMenuDataLoaded = () => useGameStore((state) => state.menuSort?.length > 0);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
interface UseGameMenuTabsReturn {
|
|
|
|
|
|
activeMainMenuTab: string;
|
|
|
|
|
|
setActiveMainMenuTab: (key: string) => void;
|
|
|
|
|
|
activeSubMenuTab: string;
|
|
|
|
|
|
setActiveSubMenuTab: (key: string) => void;
|
|
|
|
|
|
setActiveMenuTabs: (mainMenuKey: string, subMenuKey: string) => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-12 00:13:26 +08:00
|
|
|
|
/**
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* 游戏菜单选中状态统一管理 Hook
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* 统一管理主菜单和子菜单的选中状态,支持:
|
|
|
|
|
|
* - 从 gameStore 获取当前选中的主菜单和子菜单
|
|
|
|
|
|
* - 更新选中状态并自动保存到 session storage
|
|
|
|
|
|
* - 页面刷新后自动恢复选中状态
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* @returns {Object} 包含主菜单和子菜单的选中状态和更新方法
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @example
|
|
|
|
|
|
* ```typescript
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* const { activeMainMenuTab, setActiveMainMenuTab, activeSubMenuTab, setActiveSubMenuTab } = useGameMenuTabs();
|
|
|
|
|
|
*
|
|
|
|
|
|
* // 获取当前选中的主菜单
|
|
|
|
|
|
* console.log(activeMainMenuTab); // '103'
|
|
|
|
|
|
*
|
|
|
|
|
|
* // 更新选中的主菜单
|
|
|
|
|
|
* setActiveMainMenuTab('1');
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* // 获取当前选中的子菜单
|
|
|
|
|
|
* console.log(activeSubMenuTab); // '1001'
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* // 更新选中的子菜单
|
|
|
|
|
|
* setActiveSubMenuTab('1002');
|
2025-11-12 00:13:26 +08:00
|
|
|
|
* ```
|
|
|
|
|
|
*/
|
2025-11-13 16:47:10 +08:00
|
|
|
|
export const useGameMenuTabs = (): UseGameMenuTabsReturn => {
|
|
|
|
|
|
// 从 store 获取状态
|
|
|
|
|
|
const activeMainMenuTab = useGameStore((state) => state.activeMainMenuTab);
|
|
|
|
|
|
const activeSubMenuTab = useGameStore((state) => state.activeSubMenuTab);
|
|
|
|
|
|
const setActiveMenuTabsInStore = useGameStore((state) => state.setActiveMenuTabs);
|
|
|
|
|
|
const setActiveMainMenuTabInStore = useGameStore((state) => state.setActiveMainMenuTab);
|
|
|
|
|
|
const setActiveSubMenuTabInStore = useGameStore((state) => state.setActiveSubMenuTab);
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化时从 session storage 恢复选中状态
|
2025-11-12 00:13:26 +08:00
|
|
|
|
useEffect(() => {
|
2025-11-13 16:47:10 +08:00
|
|
|
|
const initializeMenuTabs = async () => {
|
2025-11-12 00:13:26 +08:00
|
|
|
|
try {
|
2025-11-13 16:47:10 +08:00
|
|
|
|
const savedMainTab = storageManager.session.getItem(STORAGE_KEYS.APP_ACTIVE_MAIN_MENU_TAB);
|
|
|
|
|
|
const savedSubTab = storageManager.session.getItem(STORAGE_KEYS.APP_ACTIVE_SUB_MENU_TAB);
|
|
|
|
|
|
|
|
|
|
|
|
if (savedMainTab) {
|
|
|
|
|
|
setActiveMainMenuTabInStore(savedMainTab);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (savedSubTab) {
|
|
|
|
|
|
setActiveSubMenuTabInStore(savedSubTab);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2025-11-13 16:47:10 +08:00
|
|
|
|
console.error('Failed to restore menu tabs:', error);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
initializeMenuTabs();
|
|
|
|
|
|
}, [setActiveMainMenuTabInStore, setActiveSubMenuTabInStore]);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新全部菜单的回调函数
|
|
|
|
|
|
const setActiveMenuTabs = useCallback(
|
|
|
|
|
|
(mainMenuKey: string, subMenuKey: string) => {
|
|
|
|
|
|
setActiveMenuTabsInStore(mainMenuKey, subMenuKey);
|
|
|
|
|
|
},
|
|
|
|
|
|
[setActiveMenuTabsInStore]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新主菜单的回调函数
|
|
|
|
|
|
const setActiveMainMenuTab = useCallback(
|
|
|
|
|
|
(key: string) => {
|
|
|
|
|
|
setActiveMainMenuTabInStore(key);
|
|
|
|
|
|
},
|
|
|
|
|
|
[setActiveMainMenuTabInStore]
|
|
|
|
|
|
);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
// 更新子菜单的回调函数
|
|
|
|
|
|
const setActiveSubMenuTab = useCallback(
|
|
|
|
|
|
(key: string) => {
|
|
|
|
|
|
setActiveSubMenuTabInStore(key);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
},
|
2025-11-13 16:47:10 +08:00
|
|
|
|
[setActiveSubMenuTabInStore]
|
2025-11-12 00:13:26 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
2025-11-13 16:47:10 +08:00
|
|
|
|
setActiveMenuTabs,
|
|
|
|
|
|
activeMainMenuTab,
|
|
|
|
|
|
setActiveMainMenuTab,
|
|
|
|
|
|
activeSubMenuTab,
|
|
|
|
|
|
setActiveSubMenuTab,
|
2025-11-12 00:13:26 +08:00
|
|
|
|
};
|
|
|
|
|
|
};
|