dict.ts 2.28 KB
import { defineStore } from 'pinia'
import { DictDataApi, type DictDataVO } from '@/api/system/dict'

export type { DictDataVO }

/**
 * 字典 store:把字典项缓存在内存,页面用 getDictOptions / getDictLabel 取
 *
 * 数据来源 `/admin-api/system/dict-data/list?dictType=xxx`(不分页)。
 *
 * ⚠️ 取字典是**异步**的:`getDictOptions()` 首次调用只返回 `[]` 并触发加载,
 *    数据回来后靠 `dictMap` 的响应式更新驱动依赖它的 computed 重算。
 *    所以调用方必须写在 `computed` 里(如 `DictTag` 组件),
 *    **不能在 `onMounted` 里调一次再把结果存进普通变量**——那样拿到的是空数组。
 *
 * ⚠️ 请求失败被静默吞掉并缓存为空数组:字典加载失败不应该让整个页面报错,
 *    `getDictLabel` 找不到就回退成原始值(数字/字符串原样显示)。
 */
export const useDictStore = defineStore('dict', () => {
  /** dictType → 字典项 */
  const dictMap = ref<Record<string, DictDataVO[]>>({})
  /** 正在请求中的 dictType,避免并发重复请求 */
  const loading = new Set<string>()

  async function loadDict(dictType: string): Promise<DictDataVO[]> {
    if (!dictType) return []
    if (dictMap.value[dictType]) return dictMap.value[dictType]
    if (loading.has(dictType)) return []
    loading.add(dictType)
    try {
      const list = await DictDataApi.getDictDataList(dictType)
      dictMap.value[dictType] = list || []
    } catch (e) {
      dictMap.value[dictType] = []
    } finally {
      loading.delete(dictType)
    }
    return dictMap.value[dictType]
  }

  function getDictOptions(dictType: string): DictDataVO[] {
    if (!dictMap.value[dictType]) loadDict(dictType)
    return dictMap.value[dictType] || []
  }

  /** 取字典显示文案;没有字典时回退原始值 */
  function getDictLabel(dictType: string, value: any): string {
    if (value === undefined || value === null || value === '') return ''
    const item = getDictOptions(dictType).find((d) => String(d.value) === String(value))
    return item ? item.label : String(value)
  }

  /** 清空缓存(登出、或字典页增删改后强制重取) */
  function reset() {
    dictMap.value = {}
  }

  return { dictMap, loadDict, getDictOptions, getDictLabel, reset }
})