外观
字典数据
字典数据
全局缓存
用户登录成功后,前端会自动调用接口从后端获取全量的字典数据,缓存在 sessionStorage
中。
- 前端在使用到字典数据时,无需重复请求后端,提升用户体验。
- 当字典数据发生变化时,需要用户 F5 刷新浏览器,进行重新加载。
文件:src\store\modules\dict.ts
使用 Pinia 和 sessionStorage 实现了一个字典数据的全局缓存管理模块。
- 定义 Store:通过
defineStore
创建名为 dict 的 store,用于管理字典数据。 - 状态管理:
- dictMap: 存储字典数据的 Map,键为 dictType,值为对应的 dictValue 列表。
- isSetDict: 标记是否已加载字典数据。
- 获取缓存数据:
getDictMap
: 从 sessionStorage 中读取缓存的字典数据。 - 设置字典数据:
setDictMap
: 若缓存存在则直接使用;否则调用接口获取并构建字典 Map,然后缓存到 sessionStorage。 - 按类型获取字典:
getDictByType
: 根据 dictType 获取对应的字典列表,若未加载则自动加载。 - 重置字典缓存:
resetDict
: 清除缓存后重新加载字典数据并重新缓存。 - 无上下文使用 Store:useDictStoreWithOut: 提供一个无需传入 store 即可使用的快捷方式。
ts
export const useDictStore = defineStore('dict', {
state: (): DictState => ({
dictMap: new Map<string, any>(),
isSetDict: false
}),
getters: {
getDictMap(): Recordable {
const dictMap = wsCache.get(CACHE_KEY.DICT_CACHE)
if (dictMap) {
this.dictMap = dictMap
}
return this.dictMap
},
getIsSetDict(): boolean {
return this.isSetDict
}
},
actions: {
async setDictMap() {
const dictMap = wsCache.get(CACHE_KEY.DICT_CACHE)
if (dictMap) {
this.dictMap = dictMap
this.isSetDict = true
} else {
const res = await getSimpleDictDataList()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
// 获得 dictType 层级
const enumValueObj = dictDataMap[dictData.dictType]
if (!enumValueObj) {
dictDataMap[dictData.dictType] = []
}
// 处理 dictValue 层级
dictDataMap[dictData.dictType].push({
value: dictData.value,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass
})
})
this.dictMap = dictDataMap
this.isSetDict = true
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 }) // 60 秒 过期
}
},
getDictByType(type: string) {
if (!this.isSetDict) {
this.setDictMap()
}
return this.dictMap[type]
},
async resetDict() {
wsCache.delete(CACHE_KEY.DICT_CACHE)
const res = await getSimpleDictDataList()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
// 获得 dictType 层级
const enumValueObj = dictDataMap[dictData.dictType]
if (!enumValueObj) {
dictDataMap[dictData.dictType] = []
}
// 处理 dictValue 层级
dictDataMap[dictData.dictType].push({
value: dictData.value,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass
})
})
this.dictMap = dictDataMap
this.isSetDict = true
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 }) // 60 秒 过期
}
}
})
字典类型
文件:src\utils\dict.ts
,定义了字典的 KEY。后续如果有新的字典 KEY,需要添加到这里。
ts
export enum DICT_TYPE {
USER_TYPE = 'user_type',
COMMON_STATUS = 'common_status',
TERMINAL = 'terminal', // 终端
DATE_INTERVAL = 'date_interval', // 数据间隔
// ========== SYSTEM 模块 ==========
SYSTEM_USER_SEX = 'system_user_sex',
SYSTEM_MENU_TYPE = 'system_menu_type',
SYSTEM_ROLE_TYPE = 'system_role_type',
...
TIP
配合《后端手册——字典管理》使用
字典使用
字典标签
文件:src\components\DictTag\index.ts
,定义了字典标签DictTag
组件。根据字典数据渲染一个或多个带颜色标签(ElTag
),支持多种类型的输入值,并自动匹配对应的字典选项显示标签。
- 例如:src\views\system\loginlog\index.vue
vue
<el-table-column label="登陆结果" align="center" prop="result">
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_LOGIN_RESULT" :value="scope.row.result" />
</template>
</el-table-column>
- 显示效果
如果使用 CRUD schemas 方式,不需要直接使用 <dict-tag />
,而是通过 columns
的 dictType
和 dictClass
属性即可。
- 例如:src\views\system\mail\account\account.data.ts
- 显示效果
字典工具类
文件:src\utils\dict.ts
,定义了字典工具。
- 获取数据字典:通过 getDictOptions 获取指定类型的数据字典列表;
- 类型转换获取字典:提供 getIntDictOptions、getStrDictOptions、getBoolDictOptions 方法分别以 number、string、boolean 类型返回值;
- 获取字典对象和标签:getDictObj 获取匹配的字典对象,getDictLabel 获取对应值的显示文本;
ts
// 获取 dictType 对应的数据字典数组【object】
export const getDictOptions = (dictType: string) => {{ /** 省略代码 */ }
// 获取 dictType 对应的数据字典数组【int】
export const getIntDictOptions = (dictType: string) => { /** 省略代码 */ }
// 获取 dictType 对应的数据字典数组【string】
export const getStrDictOptions = (dictType: string) => { /** 省略代码 */ }
// 获取 dictType 对应的数据字典数组【boolean】
export const getBoolDictOptions = (dictType: string) => { /** 省略代码 */ }
// 获取 dictType 对应的数据字典数组【object】
export const getDictObj = (dictType: string, value: any) => { /** 省略代码 */ }
// 获得字典数据的文本展示
export const getDictLabel = (dictType: string, value: any): string => { /** 省略代码 */ }
使用示例
vue
<template>
<!-- radio 单选框 -->
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="parseInt(dict.value)"
>
{{dict.label}}
</el-radio>
<!-- select 下拉框 -->
<el-select
v-model="queryParams.storage"
placeholder="请选择存储器"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</template>
<script setup lang="tsx">
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
</script>
示例文件:src\views\infra\fileConfig\index.vue