数据字典文档 - 字典管理和组件使用
概述
本文档详细介绍了 VJSP Vue3 框架的数据字典管理系统。数据字典提供统一的枚举值管理方案,支持状态码、类型标识等数据的集中管理和动态加载,确保数据一致性和维护性。
字典架构
核心特性
- 统一管理:所有枚举数据集中管理,避免硬编码
- 动态加载:支持运行时动态加载字典数据
- 智能缓存:自动缓存机制,提升性能
- 类型安全:完整的 TypeScript 类型定义支持
- 错误处理:完善的错误处理和重试机制
技术栈
- Pinia 状态管理:字典数据的状态管理和缓存
- 异步加载:支持字典数据的异步获取和更新
- 组件集成:与 Element Plus 组件库深度集成
字典管理机制
字典数据存储
字典数据采用集中式存储管理:
- 内存缓存:字典数据缓存在内存中,提升访问速度
- 自动过期:缓存数据自动过期,确保数据时效性
- 强制刷新:支持手动强制刷新字典数据
字典加载流程
- 应用启动:检查缓存有效性
- 数据加载:从后端 API 获取字典数据
- 缓存更新:更新内存缓存和时间戳
- 错误处理:处理网络错误和重试逻辑
缓存策略
框架实现智能缓存策略:
- 缓存时长:5分钟自动过期
- 重试机制:最多3次重试,指数退避延迟
- 并发控制:防止重复请求,避免资源浪费
字典工具函数
基础字典访问
框架提供安全的字典访问函数,自动处理加载和错误:
getSafeDictLabel:安全获取字典标签getSafeDictValue:安全获取字典值getSafeDictOptions:安全获取字典选项列表batchGetDictLabels:批量获取字典标签hasDictType:检查字典类型是否存在
字典状态管理
通过字典存储模块管理字典数据:
getDictData:获取字典数据(自动处理缓存)getDictByType:根据类型获取字典项getDictLabel:获取字典标签getDictValue:获取字典值refreshDictData:刷新字典数据clearDictData:清空字典缓存
字典组件使用
组件集合
框架提供完整的字典组件集合:
- DictSelect:字典选择器
- DictTag:字典标签显示
- DictRadio:字典单选组件
- DictCheckbox:字典多选组件
- DictSwitch:字典开关组件
- DictCascader:字典级联选择器
组件特性
所有字典组件具备以下特性:
- 自动加载:自动加载对应字典类型的数据
- 错误处理:处理字典数据加载失败的情况
- 类型安全:完整的 TypeScript 类型支持
- 样式统一:与 Element Plus 组件风格一致
业务模块开发指南(Product 模块)
1. 定义字典类型
在字典管理系统中定义产品相关的字典类型:
product_status:产品状态字典product_category:产品分类字典product_type:产品类型字典
2. 创建产品管理页面
src/views/modules/product/list.vue
vue
<template>
<div class="product-list">
<!-- 搜索表单 -->
<el-form :model="queryParams" inline>
<el-form-item label="产品状态">
<DictSelect
v-model="queryParams.status"
dict-type="product_status"
placeholder="请选择产品状态"
clearable
/>
</el-form-item>
<el-form-item label="产品分类">
<DictSelect
v-model="queryParams.category"
dict-type="product_category"
placeholder="请选择产品分类"
clearable
/>
</el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form>
<!-- 数据表格 -->
<el-table :data="productList" v-loading="loading">
<el-table-column prop="productName" label="产品名称" />
<el-table-column prop="productCode" label="产品编码" />
<el-table-column prop="status" label="产品状态">
<template #default="{ row }">
<DictTag :value="row.status" dict-type="product_status" />
</template>
</el-table-column>
<el-table-column prop="category" label="产品分类">
<template #default="{ row }">
<DictTag :value="row.category" dict-type="product_category" />
</template>
</el-table-column>
<el-table-column prop="type" label="产品类型">
<template #default="{ row }">
<DictTag :value="row.type" dict-type="product_type" />
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useProductApi } from '@/api/modules/product'
const queryParams = ref({
status: '',
category: '',
productName: '',
})
const productList = ref([])
const loading = ref(false)
const loadProductList = async () => {
loading.value = true
try {
const response = await useProductApi().getList(queryParams.value)
productList.value = response.data.list
} finally {
loading.value = false
}
}
const handleQuery = () => {
loadProductList()
}
const resetQuery = () => {
queryParams.value = {
status: '',
category: '',
productName: '',
}
loadProductList()
}
onMounted(() => {
loadProductList()
})
</script>3. 创建产品表单页面
src/views/modules/product/form.vue
vue
<template>
<div class="product-form">
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="产品编码" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编码" />
</el-form-item>
<el-form-item label="产品状态" prop="status">
<DictRadio v-model="form.status" dict-type="product_status" />
</el-form-item>
<el-form-item label="产品分类" prop="category">
<DictSelect
v-model="form.category"
dict-type="product_category"
placeholder="请选择产品分类"
clearable
/>
</el-form-item>
<el-form-item label="产品类型" prop="type">
<DictCheckbox v-model="form.type" dict-type="product_type" placeholder="请选择产品类型" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit">保存</el-button>
<el-button @click="handleCancel">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useProductApi } from '@/api/modules/product'
const route = useRoute()
const router = useRouter()
const form = ref({
productName: '',
productCode: '',
status: '',
category: '',
type: [],
})
const rules = {
productName: [{ required: true, message: '请输入产品名称', trigger: 'blur' }],
productCode: [{ required: true, message: '请输入产品编码', trigger: 'blur' }],
status: [{ required: true, message: '请选择产品状态', trigger: 'change' }],
}
const handleSubmit = async () => {
try {
if (route.params.id) {
await useProductApi().update(route.params.id, form.value)
} else {
await useProductApi().create(form.value)
}
router.push('/product/list')
} catch (error) {
console.error('保存失败', error)
}
}
const handleCancel = () => {
router.push('/product/list')
}
onMounted(async () => {
if (route.params.id) {
const response = await useProductApi().getDetail(route.params.id)
form.value = response.data
}
})
</script>4. 使用字典工具函数
在业务逻辑中使用字典工具函数:
typescript
import { getSafeDictLabel, getSafeDictOptions } from '@/utils/dictUtils'
// 获取产品状态标签
const getProductStatusLabel = async (status: string) => {
return await getSafeDictLabel('product_status', status, '未知状态')
}
// 获取产品分类选项
const loadProductCategories = async () => {
return await getSafeDictOptions('product_category')
}
// 批量处理产品数据
const processProductData = async (products: any[]) => {
return await batchGetDictLabels(products, 'status', 'status')
}字典组件高级用法
自定义字典组件
基于现有字典组件进行扩展:
vue
<template>
<DictSelect
v-model="selectedValue"
:dict-type="dictType"
:placeholder="placeholder"
:clearable="clearable"
:filterable="filterable"
@change="handleChange"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</DictSelect>
</template>
<script setup lang="ts">
interface Props {
dictType: string
modelValue?: string | number
placeholder?: string
clearable?: boolean
filterable?: boolean
}
const props = withDefaults(defineProps<Props>(), {
placeholder: '请选择',
clearable: true,
filterable: true,
})
const emit = defineEmits<{
'update:modelValue': [value: string | number]
change: [value: string | number]
}>()
const selectedValue = computed({
get: () => props.modelValue,
set: value => emit('update:modelValue', value),
})
const handleChange = (value: string | number) => {
emit('change', value)
}
</script>字典组件组合使用
多个字典组件组合使用场景:
vue
<template>
<div class="product-filter">
<!-- 级联选择产品分类 -->
<DictCascader
v-model="selectedCategory"
dict-type="product_category"
placeholder="请选择产品分类"
show-all-levels
/>
<!-- 多选产品类型 -->
<DictCheckbox v-model="selectedTypes" dict-type="product_type" placeholder="请选择产品类型" />
<!-- 产品状态开关 -->
<DictSwitch
v-model="statusFilter"
dict-type="product_status"
active-value="1"
inactive-value="0"
/>
</div>
</template>最佳实践
字典命名规范
- 使用有意义的字典类型名称
- 保持命名一致性(小写字母+下划线)
- 避免使用过于宽泛的名称
性能优化建议
- 合理使用字典缓存,避免频繁刷新
- 批量处理字典数据,减少请求次数
- 在组件卸载时清理字典引用
错误处理策略
- 始终使用安全的字典访问函数
- 提供合理的默认值和错误提示
- 记录字典访问错误日志
常见问题
Q: 字典数据加载失败怎么办?
A: 使用安全字典函数会自动处理错误,返回默认值或空数据。
Q: 如何强制刷新字典数据?
A: 使用 refreshDictData() 方法或设置 forceRefresh: true 参数。
Q: 字典组件不显示数据怎么办?
A: 检查字典类型名称是否正确,确认后端字典数据已配置。
Q: 如何自定义字典标签样式?
A: 通过 DictTag 组件的 type 属性或自定义 CSS 类名实现样式定制。
