|
|
@@ -1,12 +1,17 @@
|
|
|
import { defineStore } from "pinia";
|
|
|
+import { localForage } from "@/utils/localforage";
|
|
|
+import { getDictDataByType } from "@/api/system/dict";
|
|
|
+
|
|
|
+const DICT_PREFIX = "dict:";
|
|
|
+const DEFAULT_TTL_MINUTES = 60;
|
|
|
|
|
|
export const useDictStore = defineStore("dict", {
|
|
|
state: () => ({
|
|
|
- dict: []
|
|
|
+ dict: [] as Array<{ key: string; value: any[] }>
|
|
|
}),
|
|
|
|
|
|
actions: {
|
|
|
- // 获取指定字典类型
|
|
|
+ // 内存读取
|
|
|
getDict(key: string) {
|
|
|
try {
|
|
|
const item = this.dict.find(item => item.key === key);
|
|
|
@@ -17,10 +22,9 @@ export const useDictStore = defineStore("dict", {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- // 设置字典数据
|
|
|
- setDict(key: string, value: any) {
|
|
|
+ // 内存写入
|
|
|
+ setDict(key: string, value: any[]) {
|
|
|
if (!key || typeof key !== "string") return;
|
|
|
- // 避免重复添加
|
|
|
const index = this.dict.findIndex(item => item.key === key);
|
|
|
if (index !== -1) {
|
|
|
this.dict[index].value = value;
|
|
|
@@ -29,24 +33,75 @@ export const useDictStore = defineStore("dict", {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- // 移除字典数据
|
|
|
- removeDict(key: string) {
|
|
|
+ // 从持久层加载(未过期则返回)
|
|
|
+ async loadFromStorage(key: string) {
|
|
|
+ const cacheKey = `${DICT_PREFIX}${key}`;
|
|
|
+ const cached = await localForage().getItem<any[]>(cacheKey);
|
|
|
+ if (cached && cached.length) {
|
|
|
+ this.setDict(key, cached);
|
|
|
+ return cached;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 写入持久层(带 TTL,单位分钟)
|
|
|
+ async persistDict(
|
|
|
+ key: string,
|
|
|
+ value: any[],
|
|
|
+ ttlMinutes = DEFAULT_TTL_MINUTES
|
|
|
+ ) {
|
|
|
+ const cacheKey = `${DICT_PREFIX}${key}`;
|
|
|
+ await localForage().setItem(cacheKey, value, ttlMinutes);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 统一拉取入口(内存→持久层→后端)
|
|
|
+ async fetchDictByType(
|
|
|
+ key: string,
|
|
|
+ opts?: { forceRefresh?: boolean; ttlMinutes?: number }
|
|
|
+ ) {
|
|
|
+ // 1) 内存命中
|
|
|
+ const inMemory = this.getDict(key);
|
|
|
+ if (inMemory && !opts?.forceRefresh) return inMemory;
|
|
|
+
|
|
|
+ // 2) 持久层命中
|
|
|
+ const fromStorage = await this.loadFromStorage(key);
|
|
|
+ if (fromStorage && !opts?.forceRefresh) return fromStorage;
|
|
|
+
|
|
|
+ // 3) 后端拉取
|
|
|
+ const resp = await getDictDataByType(key);
|
|
|
+ const dictData = resp.data.map((p: any) => ({
|
|
|
+ label: p.dictLabel,
|
|
|
+ value: p.dictValue,
|
|
|
+ class: p.listClass
|
|
|
+ }));
|
|
|
+ this.setDict(key, dictData);
|
|
|
+ await this.persistDict(
|
|
|
+ key,
|
|
|
+ dictData,
|
|
|
+ opts?.ttlMinutes ?? DEFAULT_TTL_MINUTES
|
|
|
+ );
|
|
|
+ return dictData;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除:内存 + 持久层
|
|
|
+ async removeDict(key: string) {
|
|
|
try {
|
|
|
const index = this.dict.findIndex(item => item.key === key);
|
|
|
- if (index !== -1) {
|
|
|
- this.dict.splice(index, 1);
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
+ if (index !== -1) this.dict.splice(index, 1);
|
|
|
+ await localForage().removeItem(`${DICT_PREFIX}${key}`);
|
|
|
+ return true;
|
|
|
} catch (e) {
|
|
|
console.error("移除字典失败:", e);
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- // 清空所有字典数据
|
|
|
- clearAll() {
|
|
|
+ // 清空:内存 + 持久层(仅清理字典前缀)
|
|
|
+ async clearAll() {
|
|
|
this.dict = [];
|
|
|
+ const keys = await localForage().keys();
|
|
|
+ const dictKeys = keys.filter(k => k.startsWith(DICT_PREFIX));
|
|
|
+ await Promise.all(dictKeys.map(k => localForage().removeItem(k)));
|
|
|
}
|
|
|
}
|
|
|
});
|