Skip to content

字典管理 API

移动端字典数据相关的API接口,用于获取和管理系统字典数据,支持本地缓存和动态更新。

📋 API 概览

接口列表

功能方法路径说明
获取字典数据GET/system/dict/data/type/{dictType}根据字典类型获取数据
批量获取字典POST/system/dict/data/types批量获取多个字典类型
获取字典类型GET/system/dict/type/list获取所有字典类型
搜索字典数据GET/system/dict/data/search搜索字典数据
获取字典树结构GET/system/dict/data/tree/{dictType}获取树形字典数据

🎯 基础接口实现

获取字典数据

typescript
// 字典数据类型定义
export interface DictData {
  dictCode: number
  dictSort: number
  dictLabel: string
  dictValue: string
  dictType: string
  cssClass?: string
  listClass?: string
  isDefault: 'Y' | 'N'
  status: '0' | '1' // 0正常 1停用
  remark?: string
  createTime: string
}

// 获取单个字典类型的数据
export const getDictData = (dictType: string): Promise<ApiResponse<DictData[]>> => {
  return http.get<DictData[]>(`/system/dict/data/type/${dictType}`)
}

// 使用示例
const loadUserStatus = async () => {
  try {
    const response = await getDictData('sys_user_status')
    userStatusOptions.value = response.data.map(item => ({
      label: item.dictLabel,
      value: item.dictValue,
      disabled: item.status === '1'
    }))
  } catch (error) {
    console.error('获取用户状态字典失败:', error)
  }
}

批量获取字典

typescript
// 批量获取字典请求
export interface BatchDictRequest {
  dictTypes: string[]
}

// 批量获取字典响应
export interface BatchDictResponse {
  [dictType: string]: DictData[]
}

export const getBatchDictData = (dictTypes: string[]): Promise<ApiResponse<BatchDictResponse>> => {
  return http.post<BatchDictResponse>('/system/dict/data/types', { dictTypes })
}

// 使用示例
const loadCommonDicts = async () => {
  try {
    const dictTypes = [
      'sys_user_status',
      'sys_user_sex',
      'sys_yes_no',
      'sys_notice_type',
      'sys_common_status'
    ]

    const response = await getBatchDictData(dictTypes)

    // 批量设置字典数据
    Object.entries(response.data).forEach(([dictType, dictData]) => {
      setDictData(dictType, dictData)
    })

    console.log('常用字典加载完成')
  } catch (error) {
    console.error('批量获取字典失败:', error)
  }
}

搜索字典数据

typescript
// 字典搜索参数
export interface DictSearchRequest {
  dictType?: string
  dictLabel?: string
  dictValue?: string
  status?: '0' | '1'
  pageNum?: number
  pageSize?: number
}

export const searchDictData = (params: DictSearchRequest): Promise<ApiResponse<PageResult<DictData>>> => {
  return http.get<PageResult<DictData>>('/system/dict/data/search', params)
}

// 使用示例
const searchDict = async (keyword: string) => {
  try {
    const response = await searchDictData({
      dictLabel: keyword,
      status: '0'
    })

    searchResults.value = response.data.records
  } catch (error) {
    console.error('搜索字典失败:', error)
  }
}

获取树形字典

typescript
// 树形字典数据
export interface TreeDictData extends DictData {
  children?: TreeDictData[]
  parentCode?: string
  level?: number
}

export const getTreeDictData = (dictType: string): Promise<ApiResponse<TreeDictData[]>> => {
  return http.get<TreeDictData[]>(`/system/dict/data/tree/${dictType}`)
}

// 使用示例
const loadAreaTree = async () => {
  try {
    const response = await getTreeDictData('sys_area')
    areaTreeData.value = response.data
  } catch (error) {
    console.error('获取地区树形数据失败:', error)
  }
}

💾 字典缓存管理

本地缓存实现

typescript
// 字典缓存管理器
class DictCacheManager {
  private readonly CACHE_KEY = 'dict_cache'
  private readonly VERSION_KEY = 'dict_version'
  private readonly EXPIRE_TIME = 24 * 60 * 60 * 1000 // 24小时

  // 获取缓存的字典数据
  getCachedDict(dictType: string): DictData[] | null {
    try {
      const cache = uni.getStorageSync(this.CACHE_KEY) || {}
      const dictData = cache[dictType]

      if (dictData && this.isValidCache(dictData.timestamp)) {
        return dictData.data
      }

      return null
    } catch (error) {
      console.error('获取字典缓存失败:', error)
      return null
    }
  }

  // 设置字典缓存
  setCachedDict(dictType: string, data: DictData[]): void {
    try {
      const cache = uni.getStorageSync(this.CACHE_KEY) || {}
      cache[dictType] = {
        data,
        timestamp: Date.now()
      }
      uni.setStorageSync(this.CACHE_KEY, cache)
    } catch (error) {
      console.error('设置字典缓存失败:', error)
    }
  }

  // 批量设置字典缓存
  setBatchCachedDict(dictData: BatchDictResponse): void {
    try {
      const cache = uni.getStorageSync(this.CACHE_KEY) || {}
      const timestamp = Date.now()

      Object.entries(dictData).forEach(([dictType, data]) => {
        cache[dictType] = { data, timestamp }
      })

      uni.setStorageSync(this.CACHE_KEY, cache)
    } catch (error) {
      console.error('批量设置字典缓存失败:', error)
    }
  }

  // 清除过期缓存
  clearExpiredCache(): void {
    try {
      const cache = uni.getStorageSync(this.CACHE_KEY) || {}
      const now = Date.now()

      Object.keys(cache).forEach(dictType => {
        if (!this.isValidCache(cache[dictType].timestamp)) {
          delete cache[dictType]
        }
      })

      uni.setStorageSync(this.CACHE_KEY, cache)
    } catch (error) {
      console.error('清除过期缓存失败:', error)
    }
  }

  // 清除所有字典缓存
  clearAllCache(): void {
    try {
      uni.removeStorageSync(this.CACHE_KEY)
      uni.removeStorageSync(this.VERSION_KEY)
    } catch (error) {
      console.error('清除所有缓存失败:', error)
    }
  }

  // 检查缓存是否有效
  private isValidCache(timestamp: number): boolean {
    return Date.now() - timestamp < this.EXPIRE_TIME
  }

  // 获取缓存版本
  getCacheVersion(): string | null {
    return uni.getStorageSync(this.VERSION_KEY) || null
  }

  // 设置缓存版本
  setCacheVersion(version: string): void {
    uni.setStorageSync(this.VERSION_KEY, version)
  }

  // 检查版本是否需要更新
  needUpdate(serverVersion: string): boolean {
    const localVersion = this.getCacheVersion()
    return !localVersion || localVersion !== serverVersion
  }
}

export const dictCacheManager = new DictCacheManager()

字典数据管理器

typescript
// 字典数据管理器
class DictDataManager {
  private dictStore = new Map<string, DictData[]>()
  private loadingPromises = new Map<string, Promise<DictData[]>>()

  // 获取字典数据(优先从缓存获取)
  async getDictData(dictType: string, forceRefresh = false): Promise<DictData[]> {
    // 如果已在内存中且不强制刷新,直接返回
    if (!forceRefresh && this.dictStore.has(dictType)) {
      return this.dictStore.get(dictType)!
    }

    // 如果正在加载中,返回同一个Promise
    if (this.loadingPromises.has(dictType)) {
      return this.loadingPromises.get(dictType)!
    }

    // 创建加载Promise
    const loadPromise = this.loadDictData(dictType, forceRefresh)
    this.loadingPromises.set(dictType, loadPromise)

    try {
      const data = await loadPromise
      this.dictStore.set(dictType, data)
      return data
    } finally {
      this.loadingPromises.delete(dictType)
    }
  }

  // 加载字典数据
  private async loadDictData(dictType: string, forceRefresh: boolean): Promise<DictData[]> {
    // 如果不强制刷新,先尝试从本地缓存获取
    if (!forceRefresh) {
      const cachedData = dictCacheManager.getCachedDict(dictType)
      if (cachedData) {
        return cachedData
      }
    }

    // 从服务器获取
    try {
      const response = await getDictData(dictType)
      const data = response.data

      // 更新缓存
      dictCacheManager.setCachedDict(dictType, data)

      return data
    } catch (error) {
      console.error(`获取字典 ${dictType} 失败:`, error)

      // 如果服务器请求失败,尝试使用缓存数据
      const cachedData = dictCacheManager.getCachedDict(dictType)
      if (cachedData) {
        console.warn(`使用缓存字典数据: ${dictType}`)
        return cachedData
      }

      throw error
    }
  }

  // 批量获取字典数据
  async getBatchDictData(dictTypes: string[], forceRefresh = false): Promise<BatchDictResponse> {
    const result: BatchDictResponse = {}
    const needLoadTypes: string[] = []

    // 检查哪些字典需要加载
    for (const dictType of dictTypes) {
      if (!forceRefresh && this.dictStore.has(dictType)) {
        result[dictType] = this.dictStore.get(dictType)!
      } else {
        needLoadTypes.push(dictType)
      }
    }

    // 如果有需要加载的字典,批量加载
    if (needLoadTypes.length > 0) {
      try {
        const response = await getBatchDictData(needLoadTypes)

        // 更新内存和缓存
        Object.entries(response.data).forEach(([dictType, data]) => {
          this.dictStore.set(dictType, data)
          result[dictType] = data
        })

        // 更新本地缓存
        dictCacheManager.setBatchCachedDict(response.data)
      } catch (error) {
        console.error('批量获取字典失败:', error)

        // 尝试使用缓存数据
        needLoadTypes.forEach(dictType => {
          const cachedData = dictCacheManager.getCachedDict(dictType)
          if (cachedData) {
            result[dictType] = cachedData
            this.dictStore.set(dictType, cachedData)
          }
        })
      }
    }

    return result
  }

  // 刷新字典数据
  async refreshDictData(dictType?: string): Promise<void> {
    if (dictType) {
      await this.getDictData(dictType, true)
    } else {
      // 刷新所有已加载的字典
      const dictTypes = Array.from(this.dictStore.keys())
      await this.getBatchDictData(dictTypes, true)
    }
  }

  // 预加载常用字典
  async preloadCommonDicts(): Promise<void> {
    const commonDictTypes = [
      'sys_user_status',
      'sys_user_sex',
      'sys_yes_no',
      'sys_notice_type',
      'sys_common_status',
      'sys_job_status'
    ]

    try {
      await this.getBatchDictData(commonDictTypes)
      console.log('常用字典预加载完成')
    } catch (error) {
      console.error('预加载常用字典失败:', error)
    }
  }

  // 清除字典数据
  clearDictData(dictType?: string): void {
    if (dictType) {
      this.dictStore.delete(dictType)
    } else {
      this.dictStore.clear()
    }
  }
}

export const dictDataManager = new DictDataManager()

🎨 字典工具函数

字典数据转换

typescript
// 字典值转标签
export const dictValueToLabel = (dictType: string, value: string): string => {
  const dictData = dictDataManager.dictStore.get(dictType)
  if (!dictData) return value

  const item = dictData.find(d => d.dictValue === value)
  return item?.dictLabel || value
}

// 字典标签转值
export const dictLabelToValue = (dictType: string, label: string): string => {
  const dictData = dictDataManager.dictStore.get(dictType)
  if (!dictData) return label

  const item = dictData.find(d => d.dictLabel === label)
  return item?.dictValue || label
}

// 获取字典选项(用于选择器)
export const getDictOptions = (dictType: string): Array<{ label: string; value: string; disabled?: boolean }> => {
  const dictData = dictDataManager.dictStore.get(dictType)
  if (!dictData) return []

  return dictData
    .filter(item => item.status === '0') // 只返回正常状态的数据
    .sort((a, b) => a.dictSort - b.dictSort) // 按排序号排序
    .map(item => ({
      label: item.dictLabel,
      value: item.dictValue,
      disabled: false
    }))
}

// 获取字典CSS类
export const getDictCssClass = (dictType: string, value: string): string => {
  const dictData = dictDataManager.dictStore.get(dictType)
  if (!dictData) return ''

  const item = dictData.find(d => d.dictValue === value)
  return item?.cssClass || ''
}

// 获取字典List类
export const getDictListClass = (dictType: string, value: string): string => {
  const dictData = dictDataManager.dictStore.get(dictType)
  if (!dictData) return ''

  const item = dictData.find(d => d.dictValue === value)
  return item?.listClass || ''
}

字典组合函数

typescript
// 字典数据组合函数
export function useDict(dictType: string | string[]) {
  const dictTypes = Array.isArray(dictType) ? dictType : [dictType]
  const dictData = reactive<Record<string, DictData[]>>({})
  const loading = ref(false)
  const error = ref<string | null>(null)

  // 加载字典数据
  const loadDict = async (forceRefresh = false) => {
    loading.value = true
    error.value = null

    try {
      if (dictTypes.length === 1) {
        const data = await dictDataManager.getDictData(dictTypes[0], forceRefresh)
        dictData[dictTypes[0]] = data
      } else {
        const batchData = await dictDataManager.getBatchDictData(dictTypes, forceRefresh)
        Object.assign(dictData, batchData)
      }
    } catch (err: any) {
      error.value = err.message || '加载字典失败'
      console.error('加载字典失败:', err)
    } finally {
      loading.value = false
    }
  }

  // 获取字典选项
  const getOptions = (type: string) => {
    return getDictOptions(type)
  }

  // 值转标签
  const valueToLabel = (type: string, value: string) => {
    return dictValueToLabel(type, value)
  }

  // 标签转值
  const labelToValue = (type: string, label: string) => {
    return dictLabelToValue(type, label)
  }

  // 刷新字典
  const refresh = () => {
    loadDict(true)
  }

  // 自动加载
  onMounted(() => {
    loadDict()
  })

  return {
    dictData: readonly(dictData),
    loading: readonly(loading),
    error: readonly(error),
    loadDict,
    getOptions,
    valueToLabel,
    labelToValue,
    refresh
  }
}

// 使用示例
export default defineComponent({
  setup() {
    const { dictData, loading, getOptions, valueToLabel } = useDict([
      'sys_user_status',
      'sys_user_sex'
    ])

    const userStatusOptions = computed(() => getOptions('sys_user_status'))
    const userSexOptions = computed(() => getOptions('sys_user_sex'))

    const formatUserStatus = (status: string) => {
      return valueToLabel('sys_user_status', status)
    }

    return {
      dictData,
      loading,
      userStatusOptions,
      userSexOptions,
      formatUserStatus
    }
  }
})

字典选择器组件

vue
<!-- DictSelect.vue -->
<template>
  <wd-picker
    v-model="currentValue"
    :columns="options"
    :loading="loading"
    :placeholder="placeholder"
    @confirm="handleConfirm"
  />
</template>

<script setup lang="ts">
interface Props {
  modelValue?: string
  dictType: string
  placeholder?: string
  disabled?: boolean
}

interface Emits {
  (e: 'update:modelValue', value: string): void
  (e: 'change', value: string, label: string): void
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: '请选择'
})

const emit = defineEmits<Emits>()

const { dictData, loading, getOptions } = useDict(props.dictType)

const currentValue = computed({
  get: () => props.modelValue || '',
  set: (value) => emit('update:modelValue', value)
})

const options = computed(() => getOptions(props.dictType))

const handleConfirm = (value: string) => {
  const option = options.value.find(item => item.value === value)
  emit('change', value, option?.label || '')
}
</script>

📱 移动端优化

字典数据预加载

typescript
// 应用启动时预加载字典
export const initDictData = async () => {
  try {
    // 清理过期缓存
    dictCacheManager.clearExpiredCache()

    // 预加载常用字典
    await dictDataManager.preloadCommonDicts()

    console.log('字典数据初始化完成')
  } catch (error) {
    console.error('字典数据初始化失败:', error)
  }
}

// 在 main.ts 中调用
// initDictData()

离线支持

typescript
// 监听网络状态变化
uni.onNetworkStatusChange((res) => {
  if (res.isConnected) {
    // 网络恢复时刷新字典数据
    dictDataManager.refreshDictData()
  }
})

// 获取字典数据时的离线处理
export const getDictDataOffline = async (dictType: string): Promise<DictData[]> => {
  try {
    return await dictDataManager.getDictData(dictType)
  } catch (error) {
    // 网络错误时使用缓存数据
    const cachedData = dictCacheManager.getCachedDict(dictType)
    if (cachedData) {
      uni.showToast({
        title: '使用离线数据',
        icon: 'none'
      })
      return cachedData
    }
    throw error
  }
}

字典管理API为移动端提供了完整的字典数据支持,包括缓存管理、离线支持和高性能的数据访问机制。