yunzer_go/pc/docs/pinia-dict-guide.md
2025-11-11 18:03:16 +08:00

375 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pinia 字典管理系统使用指南
## 系统架构
```
┌─────────────────────────────────────┐
│ API 接口 (getDictItemsByCode) │
│ /api/dict/items/code/{code} │
└──────────────┬──────────────────────┘
┌─────────────────────────────────────┐
│ Pinia Store (useDictStore) │
│ ✅ 自动缓存字典数据 │
│ ✅ 避免重复请求 │
│ ✅ 支持同步/异步访问 │
└──────────────┬──────────────────────┘
┌──────┴──────┐
↓ ↓
┌────────┐ ┌──────────────┐
│组件 │ │Composable │
│直接用 │ │useDict Hook │
└────────┘ └──────────────┘
```
---
## 核心文件说明
### 1. **Store**: `src/stores/dict.js`
字典数据的全局管理器
**主要方法**
```javascript
import { useDictStore } from '@/stores/dict'
const dictStore = useDictStore()
// ✅ 异步获取字典(推荐)
const items = await dictStore.getDictItems('user_status')
// ✅ 同步获取字典(已缓存时)
const items = dictStore.getDictItemsSync('user_status')
// ✅ 获取字典值对应的标签
const label = dictStore.getDictLabel('user_status', 1)
// ✅ 预加载多个字典
await dictStore.preloadDicts(['user_status', 'user_role'])
// ✅ 清空缓存
dictStore.clearCache('user_status')
```
---
---
---
## 使用场景
### 场景1在列表页加载字典
**文件**: `src/views/system/users/index.vue`
```vue
<script setup>
import { useDictStore } from '@/stores/dict'
import { ref, onMounted } from 'vue'
const dictStore = useDictStore()
const statusDict = ref([])
const fetchStatusDict = async () => {
statusDict.value = await dictStore.getDictItems('user_status')
}
onMounted(async () => {
await fetchStatusDict()
})
</script>
<template>
<!-- 传给子组件 -->
<UserEditDialog :status-dict="statusDict" />
</template>
```
---
### 场景2在编辑对话框使用字典
**文件**: `src/views/system/users/components/UserEdit.vue`
```vue
<template>
<!-- 状态选择 -->
<el-form-item label="状态">
<el-select v-model="form.status">
<el-option
v-for="item in statusDict"
:key="item.dict_value"
:label="item.dict_label"
:value="item.dict_value"
/>
</el-select>
</el-form-item>
</template>
<script setup>
const props = defineProps({
statusDict: {
type: Array,
default: () => [],
},
})
</script>
```
---
### 场景3直接使用字典Store
直接使用字典Store获取数据
```vue
<template>
<div>
<p v-if="loading">加载中...</p>
<el-select v-else v-model="status">
<el-option
v-for="item in statusDict"
:key="item.dict_value"
:label="item.dict_label"
:value="item.dict_value"
/>
</el-select>
</div>
</template>
<script setup>
import { useDictStore } from '@/stores/dict'
import { ref, onMounted } from 'vue'
const dictStore = useDictStore()
const status = ref('1')
const statusDict = ref([])
const loading = ref(false)
const fetchStatusDict = async () => {
loading.value = true
try {
const items = await dictStore.getDictItems('user_status')
statusDict.value = items
} catch (error) {
console.error('获取用户状态字典失败:', error)
statusDict.value = []
} finally {
loading.value = false
}
}
onMounted(() => {
fetchStatusDict()
})
</script>
```
---
### 场景4预加载应用启动时需要的字典
**文件**: `src/main.js`
```javascript
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { useDictStore } from '@/stores/dict'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
// 在应用启动后预加载常用字典
const dictStore = useDictStore()
await dictStore.preloadDicts([
'user_status',
'common_status',
'yes_no',
])
app.mount('#app')
```
---
## 字典数据结构
后端返回的字典数据结构:
```json
[
{
"dict_id": 1,
"dict_value": "1",
"dict_label": "启用",
"dict_type": "user_status",
"remarks": "用户启用状态",
"remark": "用户启用状态"
},
{
"dict_id": 2,
"dict_value": "0",
"dict_label": "禁用",
"dict_type": "user_status",
"remarks": "用户禁用状态",
"remark": "用户禁用状态"
}
]
```
**关键字段**
- `dict_value`: 字典值(存储在数据库中)
- `dict_label`: 字典标签(显示给用户)
- `dict_type`: 字典类型编码(如 'user_status'
---
## 最佳实践
### ✅ DO
1. **使用字符串而不是硬编码数字**
```javascript
// ✅ 好
dictStore.getDictItems('user_status')
// ❌ 差
// 避免直接使用数字,应该使用字符串
```
2. **在父组件加载,通过 props 传给子组件**
```javascript
// ✅ 父组件负责数据,子组件负责展示
// index.vue
const statusDict = await dictStore.getDictItems('user_status')
// UserEdit.vue
const props = defineProps({ statusDict: Array })
```
3. **直接使用字典Store**
```javascript
// ✅ 直接使用Store获取数据
const statusDict = await dictStore.getDictItems('user_status')
```
4. **预加载常用字典**
```javascript
// ✅ 应用启动时预加载,避免页面初始化时加载
await dictStore.preloadDicts([...])
```
### ❌ DON'T
1. **不要在多个地方重复加载同一个字典**
```javascript
// ❌ 糟糕:重复加载
// 页面A
const dict1 = await dictStore.getDictItems('user_status')
// 页面BStore 会自动缓存,但代码看起来重复)
const dict2 = await dictStore.getDictItems('user_status')
```
2. **不要忘记处理加载状态**
```javascript
// ❌ 可能展示空白
const { statusDict } = useUserStatusDict()
// ✅ 处理加载状态
const { statusDict, loading } = useUserStatusDict()
if (loading) { /* 显示加载中 */ }
```
3. **不要混用不同的字典访问方式**
```javascript
// ❌ 混乱
const dict1 = await dictStore.getDictItems('user_status')
const dict2 = dictStore.getDictItemsSync('user_role')
// ✅ 统一使用
const dict1 = await dictStore.getDictItems('user_status')
const dict2 = await dictStore.getDictItems('user_role')
```
---
## 性能优化建议
| 优化项 | 说明 |
|------|------|
| **缓存** | Store 自动缓存,同一个字典只请求一次 |
| **预加载** | 在路由切换前预加载需要的字典 |
| **同步访问** | 已加载的字典可用 `getDictItemsSync` 同步获取 |
| **避免重复** | 不要在多个组件重复请求同一个字典 |
---
## 故障排查
### 问题1状态选项为空
**原因**:字典未加载
**解决**
```javascript
// ❌ 错误:字典还未加载
const statusDict = dictStore.getDictItemsSync('user_status') // 返回 []
// ✅ 正确:等待异步加载完成
const statusDict = await dictStore.getDictItems('user_status')
```
### 问题2重复加载字典
**原因**:没有使用 Store 的缓存
**解决**
```javascript
// 所有调用都会自动使用缓存,只请求一次
await dictStore.getDictItems('user_status') // 首次:发送请求
await dictStore.getDictItems('user_status') // 第二次:返回缓存
```
### 问题3字典显示不对
**原因**value 类型不匹配(如 1 vs "1"
**解决**
```javascript
// Store 会自动处理类型匹配
const item = items.find(i =>
String(i.dict_value) === String(value) || i.dict_value === value
)
```
---
## 集成检清表
- [x] 创建 `src/stores/dict.js` - Store
- [x]`index.vue` 中导入 `useDictStore`
- [x]`UserEdit.vue` 中使用 `useDictStore` 获取字典数据
- [x] 测试字典加载和显示
- [x] 验证缓存功能(打开浏览器 DevTools 检查 Network
- [x] 预加载常用字典(可选)
---
## 相关文件修改
已修改的文件:
-`src/stores/dict.js` - 新建
-`src/views/system/users/index.vue` - 使用 `useDictStore`
-`src/views/system/users/components/UserEdit.vue` - 使用字典功能
-`src/constants/dictCodes.js` - 删除(不再需要)
-`src/composables/useDict.js` - 删除(不再需要)