init
This commit is contained in:
2025-06-27 17:42:38 +08:00
commit bd6402478b
5317 changed files with 785994 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
import { createLocalStorage } from '/@/utils/cache';
import { Memory } from './memory';
import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
import { toRaw } from 'vue';
import { useUserStoreWithOut } from '/@/store/modules/user';
const ls = createLocalStorage({ hasEncrypt: false });
const localMemory = new Memory(DEFAULT_CACHE_TIME);
export function initDictMemory() {
const localCache = ls.get(DB_DICT_DATA_KEY);
localCache && localMemory.resetCache(localCache);
localCache && initStore(localCache);
}
function initStore(cache: any) {
const userStore = useUserStoreWithOut();
const { setAllDictItems } = userStore;
setAllDictItems(cache);
}
export class Dict {
static getDict<T>(key = '') {
if (!key) {
return localMemory.getCache as Nullable<T>;
} else {
return (localMemory.get(key)?.value as Nullable<T>) || (localMemory.get(key) as Nullable<T>);
}
}
static setDict(key, value: object, immediate = false): void {
if (!key) {
localMemory.setCache(value);
} else {
localMemory.set(key, toRaw(value));
}
immediate && ls.set(DB_DICT_DATA_KEY, localMemory.getCache);
}
static store() {
ls.set(DB_DICT_DATA_KEY, localMemory.getCache);
}
static removeDict(key, immediate = false): void {
localMemory.remove(key);
immediate && ls.set(DB_DICT_DATA_KEY, localMemory.getCache);
}
static clearDict(immediate = false): void {
localMemory.clear();
immediate && ls.remove(DB_DICT_DATA_KEY);
}
}
function storageChange(e: any) {
const { key, newValue, oldValue } = e;
if (!key) {
Dict.clearDict();
return;
}
if (!!newValue && !!oldValue) {
if (DB_DICT_DATA_KEY === key) {
Dict.clearDict();
}
}
}
window.addEventListener('storage', storageChange);
+31
View File
@@ -0,0 +1,31 @@
import { getStorageShortName } from '/@/utils/env';
import { createStorage as create, CreateStorageParams } from './storageCache';
import { DEFAULT_CACHE_TIME, enableStorageEncryption } from '/@/settings/encryptionSetting';
export type Options = Partial<CreateStorageParams>;
const createOptions = (storage: Storage, options: Options = {}): Options => {
return {
// No encryption in debug mode
hasEncrypt: enableStorageEncryption,
storage,
prefixKey: getStorageShortName(),
...options,
};
};
export const WebStorage = create(createOptions(sessionStorage));
export const createStorage = (storage: Storage = sessionStorage, options: Options = {}) => {
return create(createOptions(storage, options));
};
export const createSessionStorage = (options: Options = {}) => {
return createStorage(sessionStorage, { ...options, timeout: DEFAULT_CACHE_TIME });
};
export const createLocalStorage = (options: Options = {}) => {
return createStorage(localStorage, { ...options, timeout: DEFAULT_CACHE_TIME });
};
export default WebStorage;
+7
View File
@@ -0,0 +1,7 @@
import { initPersistentMemory } from '/@/utils/cache/persistent';
import { initDictMemory } from '/@/utils/cache/dict';
export const initCache = () => {
initPersistentMemory();
initDictMemory();
};
+109
View File
@@ -0,0 +1,109 @@
import { FAKE_USER_INFO_KEY, LOGIN_INFO_KEY, PROJ_CFG_KEY, ROLES_KEY, TENANT_ID, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
import { omit } from 'lodash-es';
export interface Cache<V = any> {
value?: V;
timeoutId?: ReturnType<typeof setTimeout>;
time?: number;
alive?: number;
}
const NOT_ALIVE = 0;
export class Memory<T = any, V = any> {
private cache: { [key in keyof T]?: Cache<V> } = {};
private alive: number;
constructor(alive = NOT_ALIVE) {
// Unit second
this.alive = alive * 1000;
}
get getCache() {
return this.cache;
}
setCache(cache) {
this.cache = cache;
}
// get<K extends keyof T>(key: K) {
// const item = this.getItem(key);
// const time = item?.time;
// if (!isNullOrUnDef(time) && time < new Date().getTime()) {
// this.remove(key);
// }
// return item?.value ?? undefined;
// }
get<K extends keyof T>(key: K) {
return this.cache[key];
}
set<K extends keyof T>(key: K, value: V, expires?: number) {
let item = this.get(key);
if (!expires || (expires as number) <= 0) {
expires = this.alive;
}
if (item) {
if (item.timeoutId) {
clearTimeout(item.timeoutId);
item.timeoutId = undefined;
}
item.value = value;
} else {
item = { value, alive: expires };
this.cache[key] = item;
}
if (!expires) {
return value;
}
const now = new Date().getTime();
item.time = now + this.alive;
item.timeoutId = setTimeout(
() => {
this.remove(key);
},
expires > now ? expires - now : expires
);
return value;
}
remove<K extends keyof T>(key: K) {
const item = this.get(key);
Reflect.deleteProperty(this.cache, key);
if (item) {
clearTimeout(item.timeoutId!);
return item.value;
}
}
resetCache(cache: { [K in keyof T]: Cache }) {
Object.keys(cache).forEach((key) => {
const k = key as any as keyof T;
const item = cache[k];
if (item && item.time) {
const now = new Date().getTime();
const expire = item.time;
if (expire > now) {
this.set(k, item.value, expire);
}
}
});
}
clear() {
Object.keys(this.cache).forEach((key) => {
const item = this.cache[key];
item.timeoutId && clearTimeout(item.timeoutId);
});
//update-begin---author:liusq Date:20220108 for:不删除登录用户的租户id,其他缓存信息都清除----
this.cache = {
...omit(this.cache, [TOKEN_KEY, USER_INFO_KEY, FAKE_USER_INFO_KEY, ROLES_KEY, TENANT_ID, LOGIN_INFO_KEY, PROJ_CFG_KEY]),
};
//update-end---author:liusq Date:20220108 for:不删除登录用户的租户id,其他缓存信息都清除----
}
}
+195
View File
@@ -0,0 +1,195 @@
import type { LockInfo, LoginInfo, UserInfo } from '/#/store';
import type { ProjectConfig } from '/#/config';
import type { RouteLocationNormalized } from 'vue-router';
import { createLocalStorage, createSessionStorage } from '/@/utils/cache';
import { Memory } from './memory';
import {
APP_LOCAL_CACHE_KEY,
APP_SESSION_CACHE_KEY,
CacheTypeEnum,
LOCK_INFO_KEY,
LOGIN_INFO_KEY,
MULTIPLE_TABS_KEY,
PROJ_CFG_KEY,
ROLES_KEY,
TENANT_ID,
TOKEN_KEY,
USER_INFO_KEY,
FAKE_USER_INFO_KEY,
SPECIAL_PATH,
SPECIAL_DOWN_PATH,
} from '/@/enums/cacheEnum';
import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
import { toRaw } from 'vue';
import { omit, pick } from 'lodash-es';
import projectSetting from '/@/settings/projectSetting';
import { useUserStoreWithOut } from '/@/store/modules/user';
const { permissionCacheType } = projectSetting;
const isLocal = permissionCacheType === CacheTypeEnum.LOCAL;
interface BasicStore {
[TOKEN_KEY]: string | number | null | undefined;
[USER_INFO_KEY]: UserInfo;
[USER_INFO_KEY]: UserInfo;
[FAKE_USER_INFO_KEY]: UserInfo;
[ROLES_KEY]: string[];
[LOCK_INFO_KEY]: LockInfo;
[PROJ_CFG_KEY]: ProjectConfig;
[MULTIPLE_TABS_KEY]: RouteLocationNormalized[];
[TENANT_ID]: string;
[LOGIN_INFO_KEY]: LoginInfo;
[SPECIAL_PATH]: string;
[SPECIAL_DOWN_PATH]: string;
}
type LocalStore = BasicStore;
type SessionStore = BasicStore;
export type BasicKeys = keyof BasicStore;
type LocalKeys = keyof LocalStore;
type SessionKeys = keyof SessionStore;
const ls = createLocalStorage();
const ss = createSessionStorage();
const localMemory = new Memory(DEFAULT_CACHE_TIME);
const sessionMemory = new Memory(DEFAULT_CACHE_TIME);
export function initPersistentMemory() {
const localCache = ls.get(APP_LOCAL_CACHE_KEY);
const sessionCache = ss.get(APP_SESSION_CACHE_KEY);
localCache &&
localMemory.resetCache({
...pick(localCache, [
TOKEN_KEY,
USER_INFO_KEY,
FAKE_USER_INFO_KEY,
ROLES_KEY,
LOGIN_INFO_KEY,
PROJ_CFG_KEY,
MULTIPLE_TABS_KEY,
TENANT_ID,
SPECIAL_PATH,
SPECIAL_DOWN_PATH,
]),
});
sessionCache &&
sessionMemory.resetCache({
...pick(sessionCache, [
TOKEN_KEY,
USER_INFO_KEY,
FAKE_USER_INFO_KEY,
ROLES_KEY,
LOGIN_INFO_KEY,
PROJ_CFG_KEY,
MULTIPLE_TABS_KEY,
TENANT_ID,
SPECIAL_PATH,
SPECIAL_DOWN_PATH,
]),
});
if (isLocal) {
localCache && initStore(localCache);
} else {
sessionCache && initStore(sessionCache);
}
}
function initStore(cache: any) {
const userStore = useUserStoreWithOut();
const { setToken, setTenant, setLoginInfo, setUserInfo, setRoleList, setFakeUserInfo, setSpecialPath, setSpecialDownPath } = userStore;
setToken(cache[TOKEN_KEY]?.value || '');
setTenant(cache[TENANT_ID]?.value || null);
setLoginInfo(cache[LOGIN_INFO_KEY]?.value || null);
setUserInfo(cache[USER_INFO_KEY]?.value || null);
setFakeUserInfo(cache[FAKE_USER_INFO_KEY]?.value || '');
setRoleList(cache[ROLES_KEY]?.value || []);
setSpecialPath(cache[SPECIAL_PATH]?.value || '');
setSpecialDownPath(cache[SPECIAL_DOWN_PATH]?.value || '');
}
export class Persistent {
static getLocal<T>(key: LocalKeys) {
//update-begin---author:scott ---date:2022-10-27 fortoken过期退出重新登录,online菜单还是提示token过期----------
const globalCache = ls.get(APP_LOCAL_CACHE_KEY);
if (globalCache) {
localMemory.setCache(globalCache);
}
//update-end---author:scott ---date::2022-10-27 fortoken过期退出重新登录,online菜单还是提示token过期----------
return localMemory.get(key)?.value as Nullable<T>;
}
static setLocal(key: LocalKeys, value: LocalStore[LocalKeys], immediate = false): void {
localMemory.set(key, toRaw(value));
immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache);
}
static removeLocal(key: LocalKeys, immediate = false): void {
localMemory.remove(key);
immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache);
}
static clearLocal(immediate = false): void {
localMemory.clear();
immediate && ls.remove(APP_LOCAL_CACHE_KEY);
}
static getSession<T>(key: SessionKeys) {
return sessionMemory.get(key)?.value as Nullable<T>;
}
static setSession(key: SessionKeys, value: SessionStore[SessionKeys], immediate = false): void {
sessionMemory.set(key, toRaw(value));
immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache);
}
static removeSession(key: SessionKeys, immediate = false): void {
sessionMemory.remove(key);
immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache);
}
static clearSession(immediate = false): void {
sessionMemory.clear();
immediate && ss.remove(APP_LOCAL_CACHE_KEY);
}
static clearAll(immediate = false) {
this.clearLocal(immediate);
this.clearSession(immediate);
}
}
window.addEventListener('beforeunload', function () {
// TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题
// LOCK_INFO_KEY 在锁屏和解锁时写入,此处也不应修改
ls.set(APP_LOCAL_CACHE_KEY, {
...omit(localMemory.getCache, LOCK_INFO_KEY),
...pick(ls.get(APP_LOCAL_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, FAKE_USER_INFO_KEY, LOCK_INFO_KEY]),
});
ss.set(APP_SESSION_CACHE_KEY, {
...omit(sessionMemory.getCache, LOCK_INFO_KEY),
...pick(ss.get(APP_SESSION_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, FAKE_USER_INFO_KEY, LOCK_INFO_KEY]),
});
});
function storageChange(e: any) {
const { key, newValue, oldValue } = e;
if (!key) {
Persistent.clearAll();
return;
}
if (!!newValue && !!oldValue) {
if (APP_LOCAL_CACHE_KEY === key) {
Persistent.clearLocal();
}
if (APP_SESSION_CACHE_KEY === key) {
Persistent.clearSession();
}
}
}
window.addEventListener('storage', storageChange);
+112
View File
@@ -0,0 +1,112 @@
import { cacheCipher } from '/@/settings/encryptionSetting';
import type { EncryptionParams } from '/@/utils/cipher';
import { AesEncryption } from '/@/utils/cipher';
import { isNullOrUnDef } from '/@/utils/is';
export interface CreateStorageParams extends EncryptionParams {
prefixKey: string;
storage: Storage;
hasEncrypt: boolean;
timeout?: Nullable<number>;
}
export const createStorage = ({
prefixKey = '',
storage = sessionStorage,
key = cacheCipher.key,
iv = cacheCipher.iv,
timeout = null,
hasEncrypt = true,
}: Partial<CreateStorageParams> = {}) => {
if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) {
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!');
}
const encryption = new AesEncryption({ key, iv });
/**
*Cache class
*Construction parameters can be passed into sessionStorage, localStorage,
* @class Cache
* @example
*/
const WebStorage = class WebStorage {
private storage: Storage;
private prefixKey?: string;
private encryption: AesEncryption;
private hasEncrypt: boolean;
/**
*
* @param {*} storage
*/
constructor() {
this.storage = storage;
this.prefixKey = prefixKey;
this.encryption = encryption;
this.hasEncrypt = hasEncrypt;
}
private getKey(key: string) {
return `${this.prefixKey}${key}`.toUpperCase();
}
/**
*
* Set cache
* @param {string} key
* @param {*} value
* @expire Expiration time in seconds
* @memberof Cache
*/
set(key: string, value: any, expire: number | null = timeout) {
const stringData = JSON.stringify({
value,
time: Date.now(),
expire: !isNullOrUnDef(expire) ? new Date().getTime() + expire * 1000 : null,
});
const stringifyValue = this.hasEncrypt ? this.encryption.encryptByAES(stringData) : stringData;
this.storage.setItem(this.getKey(key), stringifyValue);
}
/**
*Read cache
* @param {string} key
* @memberof Cache
*/
get(key: string, def: any = null): any {
const val = this.storage.getItem(this.getKey(key));
if (!val) return def;
try {
const decVal = this.hasEncrypt ? this.encryption.decryptByAES(val) : val;
const data = JSON.parse(decVal);
const { value, expire } = data;
if (isNullOrUnDef(expire) || expire >= new Date().getTime()) {
return value;
}
this.remove(key);
} catch (e) {
return def;
}
}
/**
* Delete cache based on key
* @param {string} key
* @memberof Cache
*/
remove(key: string) {
this.storage.removeItem(this.getKey(key));
}
/**
* Delete all caches of this instance
*/
clear(): void {
this.storage.clear();
}
};
return new WebStorage();
};