feat: 首页更新
This commit is contained in:
@@ -13,10 +13,7 @@ export {
|
||||
export type { ApiResponse, ApiError, RequestConfig } from './network/api';
|
||||
|
||||
// Storage
|
||||
export { default as Storage, STORAGE_KEYS } from './storage';
|
||||
export { default as SessionStorage, SESSION_KEYS } from './sessionStorage';
|
||||
export { default as StorageManager } from './storageManager';
|
||||
export type { StorageType, StorageOptions } from './storageManager';
|
||||
export { default as storageManager, STORAGE_KEYS } from './storageManager';
|
||||
|
||||
// Config
|
||||
export { default as config, printConfig } from './config';
|
||||
@@ -26,13 +23,7 @@ export {
|
||||
formatDate,
|
||||
formatRelativeTime,
|
||||
formatChatTime,
|
||||
parseDate,
|
||||
isToday,
|
||||
isYesterday,
|
||||
isSameDay,
|
||||
addDays,
|
||||
subtractDays,
|
||||
startOfDay,
|
||||
endOfDay,
|
||||
} from './date';
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { router } from 'expo-router';
|
||||
import { config } from '../config';
|
||||
import { transformRequest, parseResponse } from './helper';
|
||||
import { cloneDeep, pick } from 'lodash-es';
|
||||
import { cloneDeep, pick, includes } from 'lodash-es';
|
||||
import md5 from 'md5';
|
||||
|
||||
/**
|
||||
@@ -304,6 +304,10 @@ api.interceptors.response.use(
|
||||
});
|
||||
}
|
||||
|
||||
if (includes([500, 502, 503], error.response?.status) && includes(['371130'], `${error.config?.headers?.cmdId}`)) {
|
||||
router.replace('/maintenance' as any);
|
||||
}
|
||||
|
||||
// 处理不同的错误状态码
|
||||
if (error.response) {
|
||||
const { status, data } = error.response;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { HmacMD5 } from 'crypto-js';
|
||||
import Base64 from 'crypto-js/enc-base64';
|
||||
import Latin1 from 'crypto-js/enc-latin1';
|
||||
import { Platform } from 'react-native';
|
||||
import md5 from 'md5';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import * as des from './des';
|
||||
@@ -8,11 +9,11 @@ import NetworkError from './error';
|
||||
import { toNumber, toString, startsWith, isString, isNumber } from 'lodash-es';
|
||||
import { NetworkTypeEnum } from '@/constants/network';
|
||||
import appConfig from '../config';
|
||||
// import storageManager, { STORAGE_KEYS } from '../storageManager';
|
||||
|
||||
// import NetworkError from './error'
|
||||
// import { storeToRefs, useTenantStore, useUserStore, useAppStore, start } from '../index';
|
||||
// import { isMobile, getBetPlatform } from '@star/utils';
|
||||
// import { langToNum } from '@star/languages';
|
||||
|
||||
type PlatformType = 'IOS' | 'ANDROID' | 'H5_IOS';
|
||||
|
||||
// 请求到的数据返回
|
||||
export type NetworkResponse<T> = {
|
||||
@@ -20,38 +21,16 @@ export type NetworkResponse<T> = {
|
||||
data: T;
|
||||
};
|
||||
|
||||
export const getBetPlatform = (isReturnIndex = false) => {
|
||||
const getBetPlatform = (): PlatformType => {
|
||||
// 5=PC; 7=HOMESCREEN_IOS; 6=HOMESCREEN_ANDROID; 4=H5_IOS 3=IOS 2=H5_ANDROID; 1=ANDROID 8=马甲包
|
||||
return 'H5_IOS';
|
||||
// const platform = new URLSearchParams(window.location.search).get('platform');
|
||||
// if (platform) {
|
||||
// return platform?.includes('IOS') ? 'IOS' : platform?.includes('ANDROID') ? 'ANDROID' : '';
|
||||
// }
|
||||
// if (isAppMJB()) {
|
||||
// return 'APPS_ANDROID';
|
||||
// }
|
||||
// if (isPWA()) {
|
||||
// if (isIOS()) {
|
||||
// return isReturnIndex ? 4 : 'HS_IOS';
|
||||
// } else {
|
||||
// return isReturnIndex ? 2 : 'HS_ANDROID';
|
||||
// }
|
||||
// }
|
||||
// if (isAndroid()) {
|
||||
// if (BASE_CONFIG.appVersion > 0) {
|
||||
// return isReturnIndex ? 1 : 'ANDROID';
|
||||
// } else {
|
||||
// return isReturnIndex ? 2 : 'H5_ANDROID';
|
||||
// }
|
||||
// }
|
||||
// if (isIOS()) {
|
||||
// if (BASE_CONFIG.appVersion > 0) {
|
||||
// return isReturnIndex ? 3 : 'IOS';
|
||||
// } else {
|
||||
// return isReturnIndex ? 4 : 'H5_IOS';
|
||||
// }
|
||||
// }
|
||||
// return isReturnIndex ? 5 : 'PC';
|
||||
switch (Platform.OS) {
|
||||
case 'ios':
|
||||
return 'IOS';
|
||||
case 'android':
|
||||
return 'ANDROID';
|
||||
default:
|
||||
return 'H5_IOS';
|
||||
}
|
||||
};
|
||||
|
||||
const uuid = (len: number, radix: number) => {
|
||||
@@ -85,7 +64,7 @@ const uuid = (len: number, radix: number) => {
|
||||
};
|
||||
|
||||
// 格式化要发送的数据
|
||||
export const formatSendData = (data: any, type: number = 0) => {
|
||||
const formatSendData = (data: any, type: number = 0) => {
|
||||
// url code
|
||||
if (type === 0) {
|
||||
const arr: any[] = [];
|
||||
@@ -107,44 +86,44 @@ export const formatSendData = (data: any, type: number = 0) => {
|
||||
return JSON.stringify(data);
|
||||
};
|
||||
|
||||
export const getP = (p: any) => {
|
||||
const getP = (p: any) => {
|
||||
return HmacMD5(p, '7NEkojNzfkk=').toString();
|
||||
};
|
||||
|
||||
export const enD = (rk: string, str: string) => {
|
||||
const enD = (rk: string, str: string) => {
|
||||
const enc = des.des(rk, str, 1, 0, null, 1);
|
||||
return Base64.stringify(Latin1.parse(enc));
|
||||
};
|
||||
|
||||
export const dnD = (rk: string, str: string) => {
|
||||
const dnD = (rk: string, str: string) => {
|
||||
const s = Latin1.stringify(Base64.parse(str));
|
||||
const d = des.des(rk, s, 0, 0, null, 1);
|
||||
return d;
|
||||
};
|
||||
|
||||
export const enP = (rk: string, vk: string, t: number) => {
|
||||
const enP = (rk: string, vk: string, t: number) => {
|
||||
const enc = des.des(vk, rk + t, 1, 0, null, 1);
|
||||
return Base64.stringify(Latin1.parse(enc));
|
||||
};
|
||||
|
||||
export const dnP = (vk: string, str: string) => {
|
||||
const dnP = (vk: string, str: string) => {
|
||||
const s = Latin1.stringify(Base64.parse(str));
|
||||
const p = des.des(vk, s, 0, 0, null, 1);
|
||||
return p;
|
||||
};
|
||||
|
||||
export const enC = (rk: string, vk: string, m: string) => {
|
||||
const enC = (rk: string, vk: string, m: string) => {
|
||||
const enc = HmacMD5(m + rk, vk);
|
||||
return Base64.stringify(enc);
|
||||
};
|
||||
|
||||
export const getRequestKey = (cmdId: number, data: any) => {
|
||||
const getRequestKey = (cmdId: number, data: any) => {
|
||||
return `${cmdId}&${data ? md5(JSON.stringify(data)) : ''}`;
|
||||
};
|
||||
|
||||
// 加工请求数据
|
||||
export const transformRequest = (config: any) => {
|
||||
const { headerType = 2, paramType = 0, cmdId, tid, ...reset } = config.headers;
|
||||
const { headerType = 2, paramType = 0, cmdId, ...reset } = config.headers;
|
||||
const headers: Record<string, any> = {};
|
||||
// const { tenantInfo } = storeToRefs(useTenantStore());
|
||||
// const { userInfo } = storeToRefs(useUserStore());
|
||||
@@ -153,10 +132,8 @@ export const transformRequest = (config: any) => {
|
||||
const rk = md5(toString(Math.random() + t)).substring(0, 8);
|
||||
const vk = appConfig.app.vk as string;
|
||||
const pwds = enP(rk, vk, t);
|
||||
// const tid = cmdId !== '371130' ? storageManager.session.getItem(STORAGE_KEYS.TENANT_TID) : '';
|
||||
|
||||
const tenantInfo = {
|
||||
tid: 3,
|
||||
};
|
||||
let userInfo = {
|
||||
cust_id: '',
|
||||
cust_name: '',
|
||||
@@ -221,7 +198,7 @@ export const transformRequest = (config: any) => {
|
||||
headers.cmdId = cmdId;
|
||||
headers.aseqId = appConfig.app.aseqId;
|
||||
headers.nc = appConfig.app.nc;
|
||||
headers.tid = tid ?? tenantInfo.tid ?? '';
|
||||
headers.tid = 3;
|
||||
// 试玩游戏cust_id=0 header需要保持一致
|
||||
headers.custId = (config.data?.cust_id === 0 ? '0' : '') || userInfo?.cust_id || '';
|
||||
headers.reqId = uuid(32, 16);
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* Session Storage 实现
|
||||
*
|
||||
* React Native 没有原生的 sessionStorage,这里提供一个内存实现
|
||||
* 数据只在应用运行期间保存,应用关闭后会丢失
|
||||
*
|
||||
* 特点:
|
||||
* - 数据存储在内存中
|
||||
* - 应用重启后数据丢失
|
||||
* - 适用于临时数据、会话数据
|
||||
* - API 与 localStorage 类似
|
||||
*/
|
||||
|
||||
/**
|
||||
* Session Storage 键名常量
|
||||
*/
|
||||
export enum SESSION_KEYS {
|
||||
TEMP_DATA = 'temp_data',
|
||||
FORM_DRAFT = 'form_draft',
|
||||
SEARCH_HISTORY = 'search_history',
|
||||
CURRENT_TAB = 'current_tab',
|
||||
SCROLL_POSITION = 'scroll_position',
|
||||
FILTER_STATE = 'filter_state',
|
||||
}
|
||||
|
||||
/**
|
||||
* Session Storage 类
|
||||
*
|
||||
* 使用 Map 实现内存存储
|
||||
*/
|
||||
class SessionStorage {
|
||||
private static storage: Map<string, string> = new Map();
|
||||
|
||||
/**
|
||||
* 存储字符串
|
||||
*/
|
||||
static setString(key: string, value: string): void {
|
||||
try {
|
||||
this.storage.set(key, value);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 SessionStorage set: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage setString error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串
|
||||
*/
|
||||
static getString(key: string): string | null {
|
||||
try {
|
||||
const value = this.storage.get(key) ?? null;
|
||||
if (__DEV__) {
|
||||
console.log(`📖 SessionStorage get: ${key}`, value ? '✓' : '✗');
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage getString error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储对象(自动序列化为 JSON)
|
||||
*/
|
||||
static setObject<T>(key: string, value: T): void {
|
||||
try {
|
||||
const jsonValue = JSON.stringify(value);
|
||||
this.storage.set(key, jsonValue);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 SessionStorage set object: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage setObject error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象(自动反序列化 JSON)
|
||||
*/
|
||||
static getObject<T>(key: string): T | null {
|
||||
try {
|
||||
const jsonValue = this.storage.get(key);
|
||||
if (jsonValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
const value = JSON.parse(jsonValue) as T;
|
||||
if (__DEV__) {
|
||||
console.log(`📖 SessionStorage get object: ${key} ✓`);
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage getObject error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
static remove(key: string): void {
|
||||
try {
|
||||
this.storage.delete(key);
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ SessionStorage remove: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage remove error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储
|
||||
*/
|
||||
static clear(): void {
|
||||
try {
|
||||
this.storage.clear();
|
||||
if (__DEV__) {
|
||||
console.log('🗑️ SessionStorage cleared all');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('SessionStorage clear error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有键名
|
||||
*/
|
||||
static getAllKeys(): string[] {
|
||||
try {
|
||||
const keys = Array.from(this.storage.keys());
|
||||
if (__DEV__) {
|
||||
console.log('🔑 SessionStorage all keys:', keys);
|
||||
}
|
||||
return keys;
|
||||
} catch (error) {
|
||||
console.error('SessionStorage getAllKeys error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储项数量
|
||||
*/
|
||||
static get length(): number {
|
||||
return this.storage.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查键是否存在
|
||||
*/
|
||||
static has(key: string): boolean {
|
||||
return this.storage.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取
|
||||
*/
|
||||
static multiGet(keys: string[]): [string, string | null][] {
|
||||
try {
|
||||
return keys.map((key) => [key, this.storage.get(key) ?? null]);
|
||||
} catch (error) {
|
||||
console.error('SessionStorage multiGet error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置
|
||||
*/
|
||||
static multiSet(keyValuePairs: [string, string][]): void {
|
||||
try {
|
||||
keyValuePairs.forEach(([key, value]) => {
|
||||
this.storage.set(key, value);
|
||||
});
|
||||
if (__DEV__) {
|
||||
console.log(`💾 SessionStorage multiSet: ${keyValuePairs.length} items`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('SessionStorage multiSet error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
static multiRemove(keys: string[]): void {
|
||||
try {
|
||||
keys.forEach((key) => {
|
||||
this.storage.delete(key);
|
||||
});
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ SessionStorage multiRemove: ${keys.length} items`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('SessionStorage multiRemove error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有数据(调试用)
|
||||
*/
|
||||
static getAll(): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
this.storage.forEach((value, key) => {
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default SessionStorage;
|
||||
|
||||
184
utils/storage.ts
184
utils/storage.ts
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* AsyncStorage 封装工具
|
||||
* 提供类型安全的本地存储操作
|
||||
*/
|
||||
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
/**
|
||||
* 存储键名常量
|
||||
*/
|
||||
export enum STORAGE_KEYS {
|
||||
AUTH_TOKEN = 'auth_token',
|
||||
USER_INFO = 'user_info',
|
||||
SETTINGS = 'settings',
|
||||
THEME = 'theme',
|
||||
LANGUAGE = 'language',
|
||||
USER_PREFERENCES = 'user_preferences',
|
||||
TENANT_STORE = 'tenant_storage',
|
||||
USER_STORE = 'user_storage',
|
||||
SETTINGS_STORE = 'settings_storage',
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage 工具类
|
||||
*/
|
||||
class Storage {
|
||||
/**
|
||||
* 存储字符串
|
||||
*/
|
||||
static async setString(key: string, value: string): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.setItem(key, value);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 Storage set: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Storage setString error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串
|
||||
*/
|
||||
static async getString(key: string): Promise<string | null> {
|
||||
try {
|
||||
const value = await AsyncStorage.getItem(key);
|
||||
if (__DEV__) {
|
||||
console.log(`📖 Storage get: ${key}`, value ? '✓' : '✗');
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error(`Storage getString error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储对象(自动序列化为 JSON)
|
||||
*/
|
||||
static async setObject<T>(key: string, value: T): Promise<void> {
|
||||
try {
|
||||
const jsonValue = JSON.stringify(value);
|
||||
await AsyncStorage.setItem(key, jsonValue);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 Storage set object: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Storage setObject error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象(自动反序列化 JSON)
|
||||
*/
|
||||
static async getObject<T>(key: string): Promise<T | null> {
|
||||
try {
|
||||
const jsonValue = await AsyncStorage.getItem(key);
|
||||
if (jsonValue === null) {
|
||||
return null;
|
||||
}
|
||||
const value = JSON.parse(jsonValue) as T;
|
||||
if (__DEV__) {
|
||||
console.log(`📖 Storage get object: ${key} ✓`);
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error(`Storage getObject error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
static async remove(key: string): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.removeItem(key);
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ Storage remove: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Storage remove error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储
|
||||
*/
|
||||
static async clear(): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.clear();
|
||||
if (__DEV__) {
|
||||
console.log('🗑️ Storage cleared all');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Storage clear error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有键名
|
||||
*/
|
||||
static async getAllKeys(): Promise<string[]> {
|
||||
try {
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
if (__DEV__) {
|
||||
console.log('🔑 Storage all keys:', keys);
|
||||
}
|
||||
return keys;
|
||||
} catch (error) {
|
||||
console.error('Storage getAllKeys error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取
|
||||
*/
|
||||
static async multiGet(keys: string[]): Promise<[string, string | null][]> {
|
||||
try {
|
||||
const values = await AsyncStorage.multiGet(keys);
|
||||
return values;
|
||||
} catch (error) {
|
||||
console.error('Storage multiGet error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置
|
||||
*/
|
||||
static async multiSet(keyValuePairs: [string, string][]): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.multiSet(keyValuePairs);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 Storage multiSet: ${keyValuePairs.length} items`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Storage multiSet error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
static async multiRemove(keys: string[]): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.multiRemove(keys);
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ Storage multiRemove: ${keys.length} items`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Storage multiRemove error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Storage;
|
||||
@@ -1,242 +1,307 @@
|
||||
/**
|
||||
* 统一存储管理器
|
||||
*
|
||||
*
|
||||
* 提供统一的接口来使用 localStorage (AsyncStorage) 或 sessionStorage
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - localStorage: 持久化数据,应用重启后仍然存在
|
||||
* - sessionStorage: 临时数据,应用重启后丢失
|
||||
*
|
||||
* - local: 持久化数据,应用重启后仍然存在
|
||||
* - session: 临时数据,应用重启后丢失
|
||||
*
|
||||
* 示例:
|
||||
* ```typescript
|
||||
* // 使用 localStorage(默认)
|
||||
* await StorageManager.set('user', userData);
|
||||
*
|
||||
* // 使用 localStorage
|
||||
* await storageManager.local.setItem('user', userData);
|
||||
* const user = await storageManager.local.getItem('user');
|
||||
*
|
||||
* // 使用 sessionStorage
|
||||
* await StorageManager.set('temp', tempData, { type: 'session' });
|
||||
*
|
||||
* // 获取数据(自动从正确的存储中读取)
|
||||
* const user = await StorageManager.get('user');
|
||||
* const temp = await StorageManager.get('temp', { type: 'session' });
|
||||
* storageManager.session.setItem('temp', tempData);
|
||||
* const temp = storageManager.session.getItem('temp');
|
||||
* ```
|
||||
*/
|
||||
|
||||
import Storage from './storage';
|
||||
import SessionStorage from './sessionStorage';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
/**
|
||||
* 存储类型
|
||||
* 存储键名常量
|
||||
*/
|
||||
export type StorageType = 'local' | 'session';
|
||||
export enum STORAGE_KEYS {
|
||||
AUTH_TOKEN = 'auth_token',
|
||||
THEME = 'theme',
|
||||
LANGUAGE = 'language',
|
||||
USER_PREFERENCES = 'user_preferences',
|
||||
TENANT_STORE = 'tenant_storage',
|
||||
|
||||
/**
|
||||
* 存储选项
|
||||
*/
|
||||
export interface StorageOptions {
|
||||
/**
|
||||
* 存储类型
|
||||
* - 'local': 持久化存储(AsyncStorage)
|
||||
* - 'session': 会话存储(内存)
|
||||
*/
|
||||
type?: StorageType;
|
||||
USER_STORE = 'user_storage',
|
||||
USER_INFO = 'user_info',
|
||||
|
||||
// 游戏相关
|
||||
GAME_STORE = 'game_storage',
|
||||
GAME_TRY = 'game_try',
|
||||
|
||||
SETTINGS_STORE = 'settings_storage',
|
||||
MSG_STORE = 'msg_storage',
|
||||
TEMP_DATA = 'temp_data',
|
||||
FORM_DRAFT = 'form_draft',
|
||||
SEARCH_HISTORY = 'search_history',
|
||||
CURRENT_TAB = 'current_tab',
|
||||
SCROLL_POSITION = 'scroll_position',
|
||||
FILTER_STATE = 'filter_state',
|
||||
TENANT_TID = 'tenant_tid',
|
||||
|
||||
APP_CONFIG = 'app_config',
|
||||
APP_THEME = 'app_theme', // 主题
|
||||
APP_PLATFORM = 'app_platform', // 平台
|
||||
APP_TEMPLATE = 'app_template', // 模板
|
||||
APP_LANGUAGE = 'app_language', // 语言
|
||||
APP_ACTIVE_FOOTER_TAB_MENU = 'app_active_footer_tab_menu', // 底部菜单
|
||||
APP_MAIN_MENU = 'app_main_menu', // 首页一级菜单原始数据
|
||||
APP_ACTIVE_MAIN_MENU_TAB = 'app_active_main_menu_tab', // 游戏列表页主菜单
|
||||
APP_ACTIVE_SUB_MENU_TAB = 'app_active_sub_menu_tab', // 游戏列表页二级菜单
|
||||
APP_ACTIVE_CHILD_MENU_TAB = 'app_active_child_menu_tab', // 游戏列表页三级菜单
|
||||
APP_USER_INFO = 'app_user_info', // 登录用户信息
|
||||
POPUP_MODAL_LIST = 'app_popup_modal_list', // 首页弹窗列表
|
||||
POPUP_MODAL_STATUS_MAP = 'popup_modal_status_map', // 首页弹窗状态
|
||||
RECOVER_PASSWORD = 'recover_password', // 找回密码
|
||||
CDN_PAGE_DATA_LOADED = 'cdn_page_data_loaded', // CDN首页数据是否已加载
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一存储管理器
|
||||
* 数据类型标记
|
||||
*/
|
||||
class StorageManager {
|
||||
/**
|
||||
* 存储字符串
|
||||
*/
|
||||
static async setString(
|
||||
key: string,
|
||||
value: string,
|
||||
options: StorageOptions = {}
|
||||
): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
enum DataType {
|
||||
STRING = 'string',
|
||||
NUMBER = 'number',
|
||||
BOOLEAN = 'boolean',
|
||||
OBJECT = 'object',
|
||||
ARRAY = 'array',
|
||||
NULL = 'null',
|
||||
}
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.setString(key, value);
|
||||
} else {
|
||||
await Storage.setString(key, value);
|
||||
/**
|
||||
* 带类型标记的存储值
|
||||
*/
|
||||
interface TypedValue {
|
||||
type: DataType;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储工具基类
|
||||
* 提供公共的序列化、反序列化和类型转换方法
|
||||
*/
|
||||
abstract class StorageBase {
|
||||
/**
|
||||
* 获取数据类型
|
||||
*/
|
||||
protected static getDataType(value: any): DataType {
|
||||
if (value === null) return DataType.NULL;
|
||||
if (Array.isArray(value)) return DataType.ARRAY;
|
||||
const typeStr = typeof value;
|
||||
const dataType = DataType[typeStr.toUpperCase() as keyof typeof DataType];
|
||||
return dataType || DataType.OBJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化值(带类型标记)
|
||||
*/
|
||||
protected static serializeValue(value: any): string {
|
||||
const type = this.getDataType(value);
|
||||
const typedValue: TypedValue = {
|
||||
type,
|
||||
value: typeof value === 'string' ? value : JSON.stringify(value),
|
||||
};
|
||||
return JSON.stringify(typedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化值(自动转换类型)
|
||||
*/
|
||||
protected static deserializeValue(data: string): any {
|
||||
try {
|
||||
const typedValue: TypedValue = JSON.parse(data);
|
||||
const { type, value } = typedValue;
|
||||
|
||||
switch (type) {
|
||||
case DataType.STRING:
|
||||
return value;
|
||||
case DataType.NUMBER:
|
||||
return Number(value);
|
||||
case DataType.BOOLEAN:
|
||||
return value === 'true';
|
||||
case DataType.NULL:
|
||||
return null;
|
||||
case DataType.OBJECT:
|
||||
case DataType.ARRAY:
|
||||
return JSON.parse(value);
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('StorageBase deserialize error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地存储类(AsyncStorage)
|
||||
* 继承 StorageBase,使用其公共的序列化和反序列化方法
|
||||
*/
|
||||
class LocalStorage extends StorageBase {
|
||||
/**
|
||||
* 存储数据(自动序列化和类型标记)
|
||||
*/
|
||||
static async setItem(key: string, value: any): Promise<void> {
|
||||
try {
|
||||
const serialized = this.serializeValue(value);
|
||||
await AsyncStorage.setItem(key, serialized);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 LocalStorage set: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`LocalStorage setItem error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串
|
||||
* 获取数据(自动反序列化和类型转换)
|
||||
*/
|
||||
static async getString(
|
||||
key: string,
|
||||
options: StorageOptions = {}
|
||||
): Promise<string | null> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.getString(key);
|
||||
} else {
|
||||
return await Storage.getString(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储对象
|
||||
*/
|
||||
static async setObject<T>(
|
||||
key: string,
|
||||
value: T,
|
||||
options: StorageOptions = {}
|
||||
): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.setObject(key, value);
|
||||
} else {
|
||||
await Storage.setObject(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象
|
||||
*/
|
||||
static async getObject<T>(
|
||||
key: string,
|
||||
options: StorageOptions = {}
|
||||
): Promise<T | null> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.getObject<T>(key);
|
||||
} else {
|
||||
return await Storage.getObject<T>(key);
|
||||
static async getItem(key: string): Promise<any> {
|
||||
try {
|
||||
const value = await AsyncStorage.getItem(key);
|
||||
if (value === null) {
|
||||
if (__DEV__) {
|
||||
console.log(`📖 LocalStorage get: ${key} ✗`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const result = this.deserializeValue(value);
|
||||
if (__DEV__) {
|
||||
console.log(`📖 LocalStorage get: ${key} ✓`);
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`LocalStorage getItem error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
static async remove(key: string, options: StorageOptions = {}): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.remove(key);
|
||||
} else {
|
||||
await Storage.remove(key);
|
||||
static async removeItem(key: string): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.removeItem(key);
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ LocalStorage remove: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`LocalStorage removeItem error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空指定类型的所有存储
|
||||
* 清空所有存储
|
||||
*/
|
||||
static async clear(options: StorageOptions = {}): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.clear();
|
||||
} else {
|
||||
await Storage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有键名
|
||||
*/
|
||||
static async getAllKeys(options: StorageOptions = {}): Promise<string[]> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.getAllKeys();
|
||||
} else {
|
||||
return await Storage.getAllKeys();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查键是否存在
|
||||
*/
|
||||
static async has(key: string, options: StorageOptions = {}): Promise<boolean> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.has(key);
|
||||
} else {
|
||||
const value = await Storage.getString(key);
|
||||
return value !== null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取
|
||||
*/
|
||||
static async multiGet(
|
||||
keys: string[],
|
||||
options: StorageOptions = {}
|
||||
): Promise<[string, string | null][]> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.multiGet(keys);
|
||||
} else {
|
||||
return await Storage.multiGet(keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置
|
||||
*/
|
||||
static async multiSet(
|
||||
keyValuePairs: [string, string][],
|
||||
options: StorageOptions = {}
|
||||
): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.multiSet(keyValuePairs);
|
||||
} else {
|
||||
await Storage.multiSet(keyValuePairs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
static async multiRemove(
|
||||
keys: string[],
|
||||
options: StorageOptions = {}
|
||||
): Promise<void> {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
SessionStorage.multiRemove(keys);
|
||||
} else {
|
||||
await Storage.multiRemove(keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储大小(仅 session storage)
|
||||
*/
|
||||
static getSize(options: StorageOptions = {}): number {
|
||||
const { type = 'local' } = options;
|
||||
|
||||
if (type === 'session') {
|
||||
return SessionStorage.length;
|
||||
} else {
|
||||
// AsyncStorage 不支持直接获取大小
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储(local + session)
|
||||
*/
|
||||
static async clearAll(): Promise<void> {
|
||||
await Storage.clear();
|
||||
SessionStorage.clear();
|
||||
if (__DEV__) {
|
||||
console.log('🗑️ All storage cleared (local + session)');
|
||||
static async clear(): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.clear();
|
||||
if (__DEV__) {
|
||||
console.log('🗑️ LocalStorage cleared all');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('LocalStorage clear error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default StorageManager;
|
||||
/**
|
||||
* 会话存储类(内存实现)
|
||||
* 继承 StorageBase,使用其公共的序列化和反序列化方法
|
||||
*/
|
||||
class SessionStorage extends StorageBase {
|
||||
private static storage: Map<string, string> = new Map();
|
||||
|
||||
/**
|
||||
* 存储数据(自动序列化和类型标记)
|
||||
*/
|
||||
static setItem(key: string, value: any): void {
|
||||
try {
|
||||
const serialized = this.serializeValue(value);
|
||||
this.storage.set(key, serialized);
|
||||
if (__DEV__) {
|
||||
console.log(`💾 SessionStorage set: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage setItem error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据(自动反序列化和类型转换)
|
||||
*/
|
||||
static getItem(key: string): any {
|
||||
try {
|
||||
const value = this.storage.get(key);
|
||||
if (value === undefined) {
|
||||
if (__DEV__) {
|
||||
console.log(`📖 SessionStorage get: ${key} ✗`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const result = this.deserializeValue(value);
|
||||
if (__DEV__) {
|
||||
console.log(`📖 SessionStorage get: ${key} ✓`);
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage getItem error for key "${key}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
static removeItem(key: string): void {
|
||||
try {
|
||||
this.storage.delete(key);
|
||||
if (__DEV__) {
|
||||
console.log(`🗑️ SessionStorage remove: ${key}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`SessionStorage removeItem error for key "${key}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储
|
||||
*/
|
||||
static clear(): void {
|
||||
try {
|
||||
this.storage.clear();
|
||||
if (__DEV__) {
|
||||
console.log('🗑️ SessionStorage cleared all');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('SessionStorage clear error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一存储管理器
|
||||
*/
|
||||
const storageManager = {
|
||||
local: LocalStorage,
|
||||
session: SessionStorage,
|
||||
};
|
||||
|
||||
export default storageManager;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user