feat(字典管理): 新增字典管理功能及相关基础设施

- 新增字典管理页面,支持字典项的增删改查
- 添加 pinia-plugin-persistedstate 依赖,实现状态持久化
- 创建字典相关的 API 类型定义和服务接口
- 实现字典数据存储模块,支持字典数据的缓存和复用
- 添加 useDict 组合式函数,方便组件中使用字典数据
- 在题目分类和比赛创建模块中使用字典数据替代硬编码选项
- 优化分类树组件,添加拖拽手柄和题目类型选择
This commit is contained in:
2026-01-30 17:45:46 +08:00
parent b39761d58e
commit e1a19c48e0
21 changed files with 678 additions and 16 deletions

View File

@ -1,5 +1,6 @@
import type { App } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { resetSetupStore } from './plugins'
/** Setup Vue store plugin pinia */
@ -7,6 +8,7 @@ export function setupStore(app: App) {
const store = createPinia()
store.use(resetSetupStore)
store.use(piniaPluginPersistedstate)
app.use(store)
}

View File

@ -0,0 +1,70 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getDictionaryList, getDictionaryListUITypeByDicID } from '@/service/api/dictionary'
export const useBusinessStore = defineStore('business-store', () => {
const dictList = ref<Api.Dictionary.DictionaryItem[]>([])
const dictData = ref<Record<string, Api.Dictionary.DictionaryUIItem[]>>({})
const isInitialized = ref(false)
const loadingMap = ref<Record<string, boolean>>({})
/** 初始化字典 */
async function initDict() {
if (isInitialized.value)
return
const { data: res, error } = await getDictionaryList()
if (!error && res) {
dictList.value = res.data || []
isInitialized.value = true
}
}
/** 获取字典数据 */
async function getDict(key: string) {
if (!isInitialized.value) {
await initDict()
}
// 已经加载过,直接返回
if (dictData.value[key] && dictData.value[key].length > 0)
return dictData.value[key]
// 查找 ID
const dict = dictList.value.find(d => d.DicValue === key)
if (!dict) {
console.warn(`Dictionary key ${key} not found`)
return []
}
if (loadingMap.value[key]) {
return []
}
loadingMap.value[key] = true
try {
const { data: res, error } = await getDictionaryListUITypeByDicID(dict.Id)
if (!error && res) {
const list = res.data || []
// 使用新对象赋值,确保触发响应式更新
dictData.value = {
...dictData.value,
[key]: list,
}
}
}
finally {
loadingMap.value[key] = false
}
// eslint-disable-next-line no-console
console.log(`获取字典数据 ${key}`, dictData.value[key])
return dictData.value[key]
}
return {
dictList,
dictData,
loadingMap,
initDict,
getDict,
}
}, { persist: true })