Files
cunkebao_v3/Touchkebao/src/store/createPersistStore.ts
超级老白兔 9b3181576f feat: 初始化项目基础架构与核心功能
添加项目基础文件结构、路由配置、API接口和核心组件
实现登录认证、权限控制、WebSocket通信等基础功能
引入antd-mobile UI组件库和Vite构建工具
配置TypeScript、ESLint、Prettier等开发环境
添加移动端适配方案和全局样式
完成首页、工作台、个人中心等基础页面框架
2025-09-11 15:00:57 +08:00

262 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/store/createPersistStore.ts
import { create } from "zustand";
import { persist, PersistOptions } from "zustand/middleware";
export interface PersistConfig {
name: string;
partialize?: (state: any) => any;
storage?: Storage;
version?: number;
migrate?: (persistedState: any, version: number) => any;
onRehydrateStorage?: (state: any) => void;
skipHydration?: boolean;
compress?: boolean;
encrypt?: boolean;
ttl?: number; // 生存时间(毫秒)
encryptionKey?: string;
}
// 默认配置
const DEFAULT_CONFIG = {
storage: localStorage,
version: 1,
skipHydration: false,
compress: false,
encrypt: false,
};
// 简单的数据压缩
function compressData(data: any): string {
try {
const jsonString = JSON.stringify(data);
return btoa(encodeURIComponent(jsonString));
} catch {
return JSON.stringify(data);
}
}
// 简单的数据解压
function decompressData(compressedData: string): any {
try {
const jsonString = decodeURIComponent(atob(compressedData));
return JSON.parse(jsonString);
} catch {
return JSON.parse(compressedData);
}
}
// 简单的数据加密
function encryptData(data: string, key: string = "default-key"): string {
let result = "";
for (let i = 0; i < data.length; i++) {
result += String.fromCharCode(
data.charCodeAt(i) ^ key.charCodeAt(i % key.length),
);
}
return btoa(result);
}
// 简单的数据解密
function decryptData(
encryptedData: string,
key: string = "default-key",
): string {
try {
const data = atob(encryptedData);
let result = "";
for (let i = 0; i < data.length; i++) {
result += String.fromCharCode(
data.charCodeAt(i) ^ key.charCodeAt(i % key.length),
);
}
return result;
} catch {
return encryptedData;
}
}
// 检查数据是否过期
function isDataExpired(timestamp: number, ttl: number): boolean {
return Date.now() - timestamp > ttl;
}
export function createPersistStore<T>(
createState: (set: any, get: any) => T,
config: PersistConfig,
) {
const {
name,
partialize,
storage = DEFAULT_CONFIG.storage,
version = DEFAULT_CONFIG.version,
migrate,
onRehydrateStorage,
skipHydration = DEFAULT_CONFIG.skipHydration,
compress = DEFAULT_CONFIG.compress,
encrypt = DEFAULT_CONFIG.encrypt,
ttl,
encryptionKey = "default-key",
} = config;
return create<T>()(
persist(createState, {
name,
partialize,
storage: {
getItem: (name: string) => {
try {
const item = storage.getItem(name);
if (!item) return null;
let data: any;
try {
data = JSON.parse(item);
} catch {
return null;
}
// 检查TTL
if (data.timestamp && ttl && isDataExpired(data.timestamp, ttl)) {
storage.removeItem(name);
return null;
}
let value = data.value;
// 解密
if (encrypt && typeof value === "string") {
value = decryptData(value, encryptionKey);
}
// 解压
if (compress && typeof value === "string") {
value = decompressData(value);
}
return value;
} catch (error) {
console.warn(`Failed to get item ${name} from storage:`, error);
return null;
}
},
setItem: (name: string, value: any) => {
try {
let processedValue = value;
// 压缩
if (compress) {
processedValue = compressData(processedValue);
}
// 加密
if (encrypt && typeof processedValue === "string") {
processedValue = encryptData(processedValue, encryptionKey);
}
const storageData = {
value: processedValue,
timestamp: Date.now(),
config: { compress, encrypt, ttl },
};
storage.setItem(name, JSON.stringify(storageData));
} catch (error) {
console.warn(`Failed to set item ${name} to storage:`, error);
}
},
removeItem: (name: string) => {
try {
storage.removeItem(name);
} catch (error) {
console.warn(`Failed to remove item ${name} from storage:`, error);
}
},
},
version,
migrate,
onRehydrateStorage,
skipHydration,
} as PersistOptions<T>),
);
}
// 便利函数创建localStorage持久化store
export function createLocalStorageStore<T>(
createState: (set: any, get: any) => T,
name: string,
partialize?: (state: T) => Partial<T>,
options?: Partial<Omit<PersistConfig, "name" | "partialize" | "storage">>,
) {
return createPersistStore(createState, {
name,
partialize,
storage: localStorage,
...options,
});
}
// 便利函数创建sessionStorage持久化store
export function createSessionStorageStore<T>(
createState: (set: any, get: any) => T,
name: string,
partialize?: (state: T) => Partial<T>,
options?: Partial<Omit<PersistConfig, "name" | "partialize" | "storage">>,
) {
return createPersistStore(createState, {
name,
partialize,
storage: sessionStorage,
...options,
});
}
// 便利函数创建加密持久化store
export function createEncryptedStore<T>(
createState: (set: any, get: any) => T,
name: string,
encryptionKey: string,
partialize?: (state: T) => Partial<T>,
options?: Partial<
Omit<PersistConfig, "name" | "partialize" | "encrypt" | "encryptionKey">
>,
) {
return createPersistStore(createState, {
name,
partialize,
encrypt: true,
encryptionKey,
...options,
});
}
// 便利函数创建压缩持久化store
export function createCompressedStore<T>(
createState: (set: any, get: any) => T,
name: string,
partialize?: (state: T) => Partial<T>,
options?: Partial<Omit<PersistConfig, "name" | "partialize" | "compress">>,
) {
return createPersistStore(createState, {
name,
partialize,
compress: true,
...options,
});
}
// 便利函数创建带TTL的持久化store
export function createTTLStore<T>(
createState: (set: any, get: any) => T,
name: string,
ttl: number, // 生存时间(毫秒)
partialize?: (state: T) => Partial<T>,
options?: Partial<Omit<PersistConfig, "name" | "partialize" | "ttl">>,
) {
return createPersistStore(createState, {
name,
partialize,
ttl,
...options,
});
}