vue3项目中的字典功能

时间:2025-04-07 07:00:23

这里写自定义目录标题

  • 问题引入
  • 实现
    • 数据结构
    • 前端自定义字典数据
    • 数据加载
    • 字典挂接方法
    • el-tag插件升级
  • 使用

声明:
本方法参考“若依”平台的字典功能,部分数据结构以及后台请求方法参考该平台源代码。

问题引入

若依平台的字典模块使用简洁便利,但是仍存在一些有待改进的地方:

  • 该模块使用minxin方法在vue3中已不再被提倡;
  • 模块阅读难度较大。主要是个人水平所限;
  • 无法在el-table-column的filters中使用;
  • 无常用自定义常量的功能,如布尔型变量的展示;
  • 不能处理后台枚举类型数据;
  • 未实现数据持久化处理,需要不断请求后台数据;

实现

采用ts语言编写。

数据结构

文件名:

其中class DictData可根据自己情况添加属性

/**
 * 字典数据、字典元数据结构定义
 *@author MuYi
 *@date 2023-3-15 21:14:12
 *@version 1.0
 **/
/**
 * 后台返回数据结构,即标签和值,可能使用的字段名
 */
export const DictDataDefaultField = {
    /**
     * 默认标签字段
     */
    LABEL: ['label', 'name', 'title'],
    /**
     * 默认值字段
     */
    VALUE: ['value', 'id', 'uid', 'key'],

}
/**
 * 字典集合数据结构
 * @constructor
 */
export const DictClassData = () => {
    return {
        owner: null,
        label: {},
        type: {}
    }
}

/**
 *   字典集合类
 * @property {Object} label 字典 {字典类型名:{值:标签...}...}对象集合
 * @property {Object} dict 字典对象 {字典类型名:{}:DictData ...}字典集合
 * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
 */
export class Dict {
    private owner: null;
    public label: {};
    public type: {};

    /**
     *
     * @param typeName 指定有效时(非null或‘’),type、label数组同时初始化一个该类型名的属性
     */
    constructor(typeName?: string) {
        this.owner = null;
        this.label = {};
        this.type = {};
        if (typeName && typeName.trim() != '') {
            let name = typeName.trim();
            if (name != '') {
                this.label[name] = {};
                this.type[name] = [];
            }
        }
    }
}


/**
 * 字典数据单项结构定义
 * @property label{string} 标签
 * @property text{string} 标签,与label相同。以便直接把值付给el-table-column的filters
 * @property value {*} 值
 * @property raw 原始数据(后台java的DictData类)
 **/
export class DictData {
    label: string;
    text: string;
    value: string | number;
    raw: object;

    /**
     *
     * @param label 标签值
     * @param value 字典值
     * @param raw 原始数据
     */
    constructor(label: string, value: string | number, raw: object) {
        this.label = label
        this.text = this.label
        this.value = value
        this.raw = raw
    }
}


/**
 * 字典元数据
 * @property {String} type 类型
 * @property {Function} request 请求
 * @property {Function} responseConverter 后台数据映射方法
 * @property {String} label 标签字段
 * @property {String} value 值字段
 */
export class DictMeta {
    type: string;
    labelField: string;
    valueField: string;
    public request: object;

    /**
     *
     * @param typeName 类型
     * @param labelField 标签字段
     * @param valueField 值字段
     */
    constructor(typeName: string, labelField: string, valueField: string) {
        this.type = typeName;
        this.labelField = labelField
        this.valueField = valueField
    }
}

前端自定义字典数据

文件名:

其中:cssClass、isDefault、listClass、sort属性用于el-tag展示的样式

{
  "#说明":" 组key必须为小写,且前缀必须为'_',",
  "_boolean": [
    {
      "label": "是",
      "value": "true",
      "cssClass": "",
      "dictType": "_boolean",
      "dictValue": true,
      "isDefault": "Y",
      "listClass": "primary",
      "sort": 1
    },
    {
      "label": "否",
      "value": "false",
      "cssClass": "",
      "dictType": "_boolean",
      "dictValue": false,
      "isDefault": "N",
      "listClass": "warring",
      "sort": 2
    }
  ]
}

数据加载

文件名:

字典挂接方法

文件名:
抱歉。没****积分了,整点积分用。下载地址:全部代码

/**
 * 字典数据
 * <pre>
 * </pre>
 *@author MuYi
 *@date 2023/3/15 21:38
 *@version 1.0
 **/
import {DictData, DictMeta, Dict} from "~/composables/dict/DictDataClass";
import {getDictEnumList} from '~/api/system/dict/data'
import {requestDict} from "~/composables/dict/DictLoad";

const DEFAULT_DICT_META = {
    type: '',
    labelField: 'label',
    valueField: 'dictValue',
    request(dictType: string) {
        return getDictEnumList(dictType).then(res => (res && res.data) ? (res.data) : [{}])
    }
}
/**
 * 加载字典数据
 * <pre>
 *     dictsTypeName约定:
 *     1 枚举enum类型以Enum开头
 *     2 自定义类型以"_"开头,如"_boolean"
 *     3 其他为系统提供dictType
 * </pre>
 * @param dictsTypeName 字典名称集合。字符串数组,或以逗号分隔的字符串
 * @param config
 * @constructor
 */
export const LoadDict = (dictsTypeName: string[] | string, config = DEFAULT_DICT_META): Dict => {
    let result = new Dict(null);
    let typeNames: string[] = getDictTypeNameArray(dictsTypeName);
    if (typeNames.length < 1) return result;
    for (let typeName of typeNames) {
        config.type = typeName;
        result.type[typeName] = [];
        result.label[typeName] = [];
        let dicts = requestDict(config, result)
    }

    return result;
}

const getDictTypeNameArray = (dicts: string[] | string): string[] => {
    if (!dicts) return [];
    let result: string[];
    if (dicts instanceof Array) {
        result = dicts;
    } else {
        result = dicts.toString().split(",")
    }
    for (let i = 0; i < result.length; i++) {
        result[i] = result[i].trim();
    }
    return result
}

el-tag插件升级

注:此代码为“若依”平台源代码

使用

<script setup="SysUser" lang="ts">
//from为上述代码的存放路径
import {LoadDict} from "~/composables/dict";
 //加载数据,依次为标准后台字典类型、后台enum类、自定义类型
const dict = LoadDict(['', 'EnumExFormatType','_boolean']);
    <el-form-item label="下载类型" prop="exportType">
        <el-select>
          <el-option v-for="item in [EnumExFormatType]"
                        :key="" :label="" :value=""/>
           </el-select>
   </el-form-item> 
   <el-table-column prop="cType" label="系统级别" resizable sortable
                      :filters="['']" :filter-method="handleFilterChange">
       <template #default="scope">
           <dict-tag :options="['']" :value=""/>
       </template>
   </el-table-column>