返回博客列表

字典设计

2026-01-29
2 min read
vue

用法 useDictOptions defineStore

用法

const { options: statusOptions, load } = useDictOptions(
  'user_status',
  async () => {
    const res = await axios.get('/api/user/status')
    return res.data.data.map((item: any) => ({
      value: item.id,
      label: item.name,
      disabled: item.status === 1
    }))
  },
  { immediate: true }
)

useDictOptions

import {ref, onMounted} from 'vue'
import {useDictStore} from '@/stores/dict'

interface UseDictOptions {
    immediate?: boolean
}

/**
 * 用法示例
 * const { options: statusOptions, load } = useDictOptions(
 *   'user_status',
 *   async () => {
 *     const res = await axios.get('/api/user/status')
 *     return res.data.data.map((item: any) => ({
 *       value: item.id,
 *       label: item.name,
 *       disabled: item.status === 1
 *     }))
 *   },
 *   { immediate: true }
 * )
 * @param dictKey
 * @param converter
 * @param options
 */
export function useDictOptions(
    dictKey: string,
    converter: () => Promise<any[]>,
    options: UseDictOptions = {}
) {
    const dictStore = useDictStore()

    const opts = ref<any[]>([])

    // 加载静态字典
    const load = async () => {
        opts.value = await dictStore.fetchDict(dictKey, converter)
    }

    // 远程搜索
    const search = async (searchKey: string) => {
        opts.value = await dictStore.searchDict(dictKey, searchKey, async (key) => {
            return converter()
        })
    }

    if (options.immediate) {
        onMounted(load)
    }

    return {
        options: opts,
        load,
        search
    }
}

defineStore

import {defineStore} from 'pinia'
import {ref} from 'vue'

export const useDictStore = defineStore('dict', () => {

    const dicts = ref<Record<string, any[]>>({})

    const searchCache = ref<Record<string, Record<string, any[]>>>({})

    const timestamps = ref<Record<string, number>>({})

    const CACHE_DURATION = 10 * 60 * 1000

    const isExpired = (type: string) => {
        if (!timestamps.value[type]) return true
        return Date.now() - timestamps.value[type] > CACHE_DURATION
    }

    /**
     * 普通字典获取
     */
    const fetchDict = async (type: string, converter: () => Promise<any[]>) => {
        if (!dicts.value[type] || isExpired(type)) {
            dicts.value[type] = await converter()
            timestamps.value[type] = Date.now()
        }
        return dicts.value[type]
    }

    /**
     * 远程搜索字典
     * @param type 字典类型
     * @param searchKey 搜索关键字
     * @param converter 转换函数,接收 searchKey 返回字典数组
     * @param cache 是否缓存结果
     */
    const searchDict = async (
        type: string,
        searchKey: string,
        converter: (searchKey: string) => Promise<any[]>,
        cache = true
    ) => {
        if (cache && searchCache.value[type]?.[searchKey]) {
            return searchCache.value[type][searchKey]
        }

        const result = await converter(searchKey)

        if (cache) {
            if (!searchCache.value[type]) searchCache.value[type] = {}
            searchCache.value[type][searchKey] = result
        }

        return result
    }

    const clearDict = (type?: string) => {
        if (type) {
            delete dicts.value[type]
            delete timestamps.value[type]
            delete searchCache.value[type]
        } else {
            dicts.value = {}
            timestamps.value = {}
            searchCache.value = {}
        }
    }

    return {
        fetchDict,
        searchDict,
        clearDict,
        isExpired
    }
})

返回博客列表
最后更新于 2026-01-29
想法或问题?在 GitHub Issue 下方参与讨论
去评论