字典设计
vue
用法
text
1const { options: statusOptions, load } = useDictOptions(
2 'user_status',
3 async () => {
4 const res = await axios.get('/api/user/status')
5 return res.data.data.map((item: any) => ({
6 value: item.id,
7 label: item.name,
8 disabled: item.status === 1
9 }))
10 },
11 { immediate: true }
12)useDictOptions
text
1import {ref, onMounted} from 'vue'
2import {useDictStore} from '@/stores/dict'
3
4interface UseDictOptions {
5 immediate?: boolean
6}
7
8/**
9 * 用法示例
10 * const { options: statusOptions, load } = useDictOptions(
11 * 'user_status',
12 * async () => {
13 * const res = await axios.get('/api/user/status')
14 * return res.data.data.map((item: any) => ({
15 * value: item.id,
16 * label: item.name,
17 * disabled: item.status === 1
18 * }))
19 * },
20 * { immediate: true }
21 * )
22 * @param dictKey
23 * @param converter
24 * @param options
25 */
26export function useDictOptions(
27 dictKey: string,
28 converter: () => Promise<any[]>,
29 options: UseDictOptions = {}
30) {
31 const dictStore = useDictStore()
32
33 const opts = ref<any[]>([])
34
35 // 加载静态字典
36 const load = async () => {
37 opts.value = await dictStore.fetchDict(dictKey, converter)
38 }
39
40 // 远程搜索
41 const search = async (searchKey: string) => {
42 opts.value = await dictStore.searchDict(dictKey, searchKey, async (key) => {
43 return converter()
44 })
45 }
46
47 if (options.immediate) {
48 onMounted(load)
49 }
50
51 return {
52 options: opts,
53 load,
54 search
55 }
56}
57defineStore
text
1import {defineStore} from 'pinia'
2import {ref} from 'vue'
3
4export const useDictStore = defineStore('dict', () => {
5
6 const dicts = ref<Record<string, any[]>>({})
7
8 const searchCache = ref<Record<string, Record<string, any[]>>>({})
9
10 const timestamps = ref<Record<string, number>>({})
11
12 const CACHE_DURATION = 10 * 60 * 1000
13
14 const isExpired = (type: string) => {
15 if (!timestamps.value[type]) return true
16 return Date.now() - timestamps.value[type] > CACHE_DURATION
17 }
18
19 /**
20 * 普通字典获取
21 */
22 const fetchDict = async (type: string, converter: () => Promise<any[]>) => {
23 if (!dicts.value[type] || isExpired(type)) {
24 dicts.value[type] = await converter()
25 timestamps.value[type] = Date.now()
26 }
27 return dicts.value[type]
28 }
29
30 /**
31 * 远程搜索字典
32 * @param type 字典类型
33 * @param searchKey 搜索关键字
34 * @param converter 转换函数,接收 searchKey 返回字典数组
35 * @param cache 是否缓存结果
36 */
37 const searchDict = async (
38 type: string,
39 searchKey: string,
40 converter: (searchKey: string) => Promise<any[]>,
41 cache = true
42 ) => {
43 if (cache && searchCache.value[type]?.[searchKey]) {
44 return searchCache.value[type][searchKey]
45 }
46
47 const result = await converter(searchKey)
48
49 if (cache) {
50 if (!searchCache.value[type]) searchCache.value[type] = {}
51 searchCache.value[type][searchKey] = result
52 }
53
54 return result
55 }
56
57 const clearDict = (type?: string) => {
58 if (type) {
59 delete dicts.value[type]
60 delete timestamps.value[type]
61 delete searchCache.value[type]
62 } else {
63 dicts.value = {}
64 timestamps.value = {}
65 searchCache.value = {}
66 }
67 }
68
69 return {
70 fetchDict,
71 searchDict,
72 clearDict,
73 isExpired
74 }
75})
76