backend/src/stores/dict.js
2026-01-26 09:32:17 +08:00

180 lines
4.6 KiB
JavaScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { getDictItemsByCode } from '@/api/dict'
/**
* 字典 Store
*
* 用于全局管理系统字典数据
* 缓存字典数据避免重复请求,提高性能
*
* 使用示例:
* const dictStore = useDictStore()
* const statusDict = await dictStore.getDictItems('user_status')
* const roleDict = dictStore.getDictItemsSync('user_role') // 已加载则同步返回
*/
export const useDictStore = defineStore('dict', () => {
// 字典缓存:{ dictCode: [...items] }
const dictCache = ref({})
// 正在加载的字典代码集合
const loadingCodes = ref(new Set())
/**
* 获取字典项(异步)
* @param {string} code - 字典编码,如 'user_status'
* @returns {Promise<Array>} 字典项数组
*/
async function getDictItems(code) {
// 如果缓存中已有,直接返回
if (dictCache.value[code]) {
return dictCache.value[code]
}
// 避免重复请求:如果已在加载中,等待
if (loadingCodes.value.has(code)) {
// 等待加载完成(最多 5 秒)
return await new Promise((resolve) => {
let count = 0
const timer = setInterval(() => {
if (dictCache.value[code]) {
clearInterval(timer)
resolve(dictCache.value[code])
}
count++
if (count > 50) {
clearInterval(timer)
resolve([])
}
}, 100)
})
}
// 标记为正在加载
loadingCodes.value.add(code)
try {
const res = await getDictItemsByCode(code)
let items = []
// 兼容不同的 API 响应格式
if (res?.data && Array.isArray(res.data)) {
items = res.data
} else if (Array.isArray(res)) {
items = res
} else if (res?.data?.data && Array.isArray(res.data.data)) {
items = res.data.data
}
// 缓存字典项
dictCache.value[code] = items
// console.log(`✅ 字典 [${code}] 已加载,共 ${items.length} 项`)
return items
} catch (error) {
console.error(`❌ 加载字典 [${code}] 失败:`, error)
dictCache.value[code] = []
return []
} finally {
// 移除加载标记
loadingCodes.value.delete(code)
}
}
/**
* 同步获取字典项(如果已缓存)
* @param {string} code - 字典编码
* @returns {Array} 字典项数组,未缓存则返回空数组
*/
function getDictItemsSync(code) {
return dictCache.value[code] || []
}
/**
* 预加载字典(在应用启动时调用)
* @param {Array<string>} codes - 字典编码数组
* @returns {Promise<void>}
*/
async function preloadDicts(codes) {
const promises = codes.map(code => getDictItems(code))
await Promise.all(promises)
}
/**
* 根据字典编码和值获取标签
* @param {string} code - 字典编码
* @param {any} value - 字典值
* @returns {string} 字典标签
*/
function getDictLabel(code, value) {
const items = getDictItemsSync(code)
if (!items.length) {
console.warn(`⚠️ 字典 [${code}] 未加载,无法获取标签`)
return String(value)
}
const item = items.find(i => String(i.dict_value) === String(value) || i.dict_value === value)
return item ? item.dict_label : String(value)
}
/**
* 根据字典编码和标签获取值
* @param {string} code - 字典编码
* @param {string} label - 字典标签
* @returns {any} 字典值
*/
function getDictValue(code, label) {
const items = getDictItemsSync(code)
if (!items.length) {
console.warn(`⚠️ 字典 [${code}] 未加载,无法获取值`)
return null
}
const item = items.find(i => i.dict_label === label)
return item ? item.dict_value : null
}
/**
* 清空缓存
* @param {string} code - 字典编码,不指定则清空所有
*/
function clearCache(code) {
if (code) {
delete dictCache.value[code]
// console.log(`✅ 已清除字典 [${code}] 缓存`)
} else {
dictCache.value = {}
// console.log(`✅ 已清除所有字典缓存`)
}
}
/**
* 刷新字典
* @param {string} code - 字典编码
* @returns {Promise<Array>}
*/
async function refreshDict(code) {
clearCache(code)
return getDictItems(code)
}
/**
* 获取所有已缓存的字典
* @returns {Object}
*/
const allDicts = computed(() => dictCache.value)
return {
dictCache,
loadingCodes,
getDictItems,
getDictItemsSync,
preloadDicts,
getDictLabel,
getDictValue,
clearCache,
refreshDict,
allDicts,
}
})