草庐IT

Ruoyi字典源码学习

allworldg 2023-03-28 原文

此文章属于ruoyi项目实战系列

使用目的

  1. 什么是字典数据:具体的值(0,1,"Y","N"),对应具体的业务逻辑("男","女","是","否")。
  2. 字典数据不应该只写死在代码中,还应存入数据库,通过管理系统来增删改查。

源码分析

ruoyi项目在低于3.7.0的版本中,前端字典功能实现比较简单,每个index.vue页面都请求dict的api,获取数据再加工显示即可。3.7.0之后的版本使用了混入,所以复杂了一些。

分析

  1. 入口:查看全局入口文件main.jsDictData.install()是字典功能的入口位置。

    function install() {
      Vue.use(DataDict, {//额外参数
        metas: {
          '*': {
            labelField: 'dictLabel',
            valueField: 'dictValue',
            request(dictMeta) {
              return getDicts(dictMeta.type).then(res => res.data)
            },
          },
        },
      })
    }
    

    install全局注册了一个插件DataDict,同时传入了额外参数{meta:xxx},目的是将DataDict插件对应的参数进行赋值。

  2. DataDict插件:因为该插件本身是个function,所以Vue.use会直接将function视为install()方法执行。

    export default function (Vue, options) {
    	mergeOptions(options)
    	Vue.mixin({...})
    }
    

    首先执行mergeOptions(options),目的是将传入的额外参数与DictOptions合并。具体实现是通过递归调用mergeRecursive(source,target),将DictOptions的属性覆盖或者添加。

    其次注册全局混入 Vue.mixin ,给所有 Vue 实例添加了 data()created() 方法。

    Vue.mixin({
    	data(){
    		const dict = new Dict()
    		dict.owner = this
    		return {dict}
    	},
    	created(){
    	....
    	this.dict.init(this.$options.dicts).then(()=>{...})
    	}
    	
    })
    

    data (): 每个 Vue 页面创建一个 Dict。

    created(): 调用Dict.init(dicts)方法,传入每个vue页面声明的dicts数组(例如 dicts['sys_normal_disable'])。(额外补充:init().then(....)里的方法个人认为是为了拓展性,因为我全局查找也没有看到任何地方用到。)

  3. Dict. init () : 看注释即可

    init(options) {  
      if (options instanceof Array) {  
        //此处传进来的是每个index.vue的dicts属性,基本上是['dictName1','dictName2']之类的。  
        options = {types: options}  
      }  
    	  const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)//options与DEFAULT合并,并且将合并结果赋值给opts  
      if (opts.types === undefined) {  
        throw new Error('need dict types')  
      }  
      const ps = []  
      this._dictMetas = opts.types.map(t => DictMeta.parse(t)) //调用parse,将数组中的字符串转换为DictMeta对象返回。 
      this._dictMetas.forEach(dictMeta => {  
        const type = dictMeta.type  
        Vue.set(this.label, type, {})//dict.label添加属性 dictName:{}
        Vue.set(this.type, type, [])//dict.type 添加属性 dictName[]
        if (dictMeta.lazy) {  
          return  
        }  
        ps.push(loadDict(this, dictMeta))  
      })loadDict:请求后端api,将数据组装进dict  
      return Promise.all(ps)  
    }
    

简单通过注释解释一下init里的一些调用函数源码

  1. DictMeta.parse

    DictMeta.parse= function(options) {  
      let opts = null  
      if (typeof options === 'string') {  
        opts = DictOptions.metas[options] || {}  
        opts.type = options//opt{type:'字典名称'}  
      } else if (typeof options === 'object') {  
        opts = options  
      }  
      //创建{type:'字典名称"}并且赋值给DictOptions.meta属性  
      opts = mergeRecursive(DictOptions.metas['*'], opts)  
      //构造dictmeta原数据  
      return new DictMeta(opts)  
    }
    

    主要将vue页面的dicts数组以及DictOption的meta数据在整合赋值到DictMeta对象,方便后续调用。

  2. loadDict(dict,dictMeta)

    function loadDict(dict, dictMeta) {  
      return dictMeta.request(dictMeta)//请求后端api,获取字典数据  
        .then(response => {  
          const type = dictMeta.type  
          let dicts = dictMeta.responseConverter(response, dictMeta)//将response转换成DictData  
          if (!(dicts instanceof Array)) {  
            console.error('the return of responseConverter must be Array.<DictData>')  
            dicts = []  
          } else if (dicts.filter(d => d instanceof DictData).length !==
           dicts.length) {  
            console.error('the type of elements in dicts must be DictData')  
            dicts = []  
          }  
          //将response的数据插入到dict.type['dictName']的数组中  
          //splice实现了响应式改变数组元素,所以这里不用vue.set  
          dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
          //将dicts(也就是dictData)赋值给dict.type[type]  
          dicts.forEach(d => {  
            Vue.set(dict.label[type], d.value, d.label)
            //dict.label{'dictName':{}}添加属性d.value:d.label  
          })  
          return dicts  
        })  
    }	
    
  3. 具体页面应用
    例如job/index.vue,

    <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>  
      <el-option  
        v-for="dict in dict.type.sys_job_status"  
        :key="dict.value"  
        :label="dict.label"  
        :value="dict.value"  
      />  
    </el-select>	
    
    export default{
    dicts:['sys_job_group','sys_job_status'],
    //dict:{'sys_job_group':[data1,data2],'sys_job_status':[data1,data2]} 通过上文的代码全局混入得到
    }
    

有关Ruoyi字典源码学习的更多相关文章

  1. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  5. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

  6. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  7. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  8. python - 将 Ruby 哈希字符串转换为 Python 字典 - 2

    我正在处理一些作为Ruby哈希字符串返回的命令输出。(来自名为mcollective的东西)。这是我收到的示例字符串:{:changes=>{"total"=>0},:events=>{"failure"=>0,"success"=>0,"total"=>0},:version=>{"puppet"=>"2.7.21(PuppetEnterprise2.8.1)","config"=>1381497648},:time=>{"filebucket"=>0.000287,"cron"=>0.00212,"package"=>0.398982,"exec"=>0.001314,"confi

  9. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  10. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

随机推荐