使用vue-data-dict,简化数据字典使用
This commit is contained in:
82
ruoyi-ui/src/utils/dict/Dict.js
Normal file
82
ruoyi-ui/src/utils/dict/Dict.js
Normal file
@ -0,0 +1,82 @@
|
||||
import Vue from 'vue'
|
||||
import { mergeRecursive } from "@/utils/ruoyi";
|
||||
import DictMeta from './DictMeta'
|
||||
import DictData from './DictData'
|
||||
|
||||
const DEFAULT_DICT_OPTIONS = {
|
||||
types: [],
|
||||
}
|
||||
|
||||
/**
|
||||
* @classdesc 字典
|
||||
* @property {Object} label 标签对象,内部属性名为字典类型名称
|
||||
* @property {Object} dict 字段数组,内部属性名为字典类型名称
|
||||
* @property {Array.<DictMeta>} _dictMetas 字典元数据数组
|
||||
*/
|
||||
export default class Dict {
|
||||
constructor() {
|
||||
this.owner = null
|
||||
this.label = {}
|
||||
this.type = {}
|
||||
}
|
||||
|
||||
init(options) {
|
||||
if (options instanceof Array) {
|
||||
options = { types: options }
|
||||
}
|
||||
const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
|
||||
if (opts.types === undefined) {
|
||||
throw new Error('need dict types')
|
||||
}
|
||||
const ps = []
|
||||
this._dictMetas = opts.types.map(t => DictMeta.parse(t))
|
||||
this._dictMetas.forEach(dictMeta => {
|
||||
const type = dictMeta.type
|
||||
Vue.set(this.label, type, {})
|
||||
Vue.set(this.type, type, [])
|
||||
if (dictMeta.lazy) {
|
||||
return
|
||||
}
|
||||
ps.push(loadDict(this, dictMeta))
|
||||
})
|
||||
return Promise.all(ps)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载字典
|
||||
* @param {String} type 字典类型
|
||||
*/
|
||||
reloadDict(type) {
|
||||
const dictMeta = this._dictMetas.find(e => e.type === type)
|
||||
if (dictMeta === undefined) {
|
||||
return Promise.reject(`the dict meta of ${type} was not found`)
|
||||
}
|
||||
return loadDict(this, dictMeta)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载字典
|
||||
* @param {Dict} dict 字典
|
||||
* @param {DictMeta} dictMeta 字典元数据
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function loadDict(dict, dictMeta) {
|
||||
return dictMeta.request(dictMeta)
|
||||
.then(response => {
|
||||
const type = dictMeta.type
|
||||
let dicts = dictMeta.responseConverter(response, dictMeta)
|
||||
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 = []
|
||||
}
|
||||
dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
|
||||
dicts.forEach(d => {
|
||||
Vue.set(dict.label[type], d.value, d.label)
|
||||
})
|
||||
return dicts
|
||||
})
|
||||
}
|
17
ruoyi-ui/src/utils/dict/DictConverter.js
Normal file
17
ruoyi-ui/src/utils/dict/DictConverter.js
Normal file
@ -0,0 +1,17 @@
|
||||
import DictOptions from './DictOptions'
|
||||
import DictData from './DictData'
|
||||
|
||||
export default function(dict, dictMeta) {
|
||||
const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
|
||||
const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
|
||||
return new DictData(dict[label], dict[value], dict)
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定字典字段
|
||||
* @param {DictData} dict
|
||||
* @param {...String} fields
|
||||
*/
|
||||
function determineDictField(dict, ...fields) {
|
||||
return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
|
||||
}
|
13
ruoyi-ui/src/utils/dict/DictData.js
Normal file
13
ruoyi-ui/src/utils/dict/DictData.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @classdesc 字典数据
|
||||
* @property {String} label 标签
|
||||
* @property {*} value 标签
|
||||
* @property {Object} raw 原始数据
|
||||
*/
|
||||
export default class DictData {
|
||||
constructor(label, value, raw) {
|
||||
this.label = label
|
||||
this.value = value
|
||||
this.raw = raw
|
||||
}
|
||||
}
|
38
ruoyi-ui/src/utils/dict/DictMeta.js
Normal file
38
ruoyi-ui/src/utils/dict/DictMeta.js
Normal file
@ -0,0 +1,38 @@
|
||||
import { mergeRecursive } from "@/utils/ruoyi";
|
||||
import DictOptions from './DictOptions'
|
||||
|
||||
/**
|
||||
* @classdesc 字典元数据
|
||||
* @property {String} type 类型
|
||||
* @property {Function} request 请求
|
||||
* @property {String} label 标签字段
|
||||
* @property {String} value 值字段
|
||||
*/
|
||||
export default class DictMeta {
|
||||
constructor(options) {
|
||||
this.type = options.type
|
||||
this.request = options.request,
|
||||
this.responseConverter = options.responseConverter
|
||||
this.labelField = options.labelField
|
||||
this.valueField = options.valueField
|
||||
this.lazy = options.lazy === true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析字典元数据
|
||||
* @param {Object} options
|
||||
* @returns {DictMeta}
|
||||
*/
|
||||
DictMeta.parse= function(options) {
|
||||
let opts = null
|
||||
if (typeof options === 'string') {
|
||||
opts = DictOptions.metas[options] || {}
|
||||
opts.type = options
|
||||
} else if (typeof options === 'object') {
|
||||
opts = options
|
||||
}
|
||||
opts = mergeRecursive(DictOptions.metas['*'], opts)
|
||||
return new DictMeta(opts)
|
||||
}
|
51
ruoyi-ui/src/utils/dict/DictOptions.js
Normal file
51
ruoyi-ui/src/utils/dict/DictOptions.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { mergeRecursive } from "@/utils/ruoyi";
|
||||
import dictConverter from './DictConverter'
|
||||
|
||||
export const options = {
|
||||
metas: {
|
||||
'*': {
|
||||
/**
|
||||
* 字典请求,方法签名为function(dictMeta: DictMeta): Promise
|
||||
*/
|
||||
request: (dictMeta) => {
|
||||
console.log(`load dict ${dictMeta.type}`)
|
||||
return Promise.resolve([])
|
||||
},
|
||||
/**
|
||||
* 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
|
||||
*/
|
||||
responseConverter,
|
||||
labelField: 'label',
|
||||
valueField: 'value',
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 默认标签字段
|
||||
*/
|
||||
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
|
||||
/**
|
||||
* 默认值字段
|
||||
*/
|
||||
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
|
||||
}
|
||||
|
||||
/**
|
||||
* 映射字典
|
||||
* @param {Object} response 字典数据
|
||||
* @param {DictMeta} dictMeta 字典元数据
|
||||
* @returns {DictData}
|
||||
*/
|
||||
function responseConverter(response, dictMeta) {
|
||||
const dicts = response.content instanceof Array ? response.content : response
|
||||
if (dicts === undefined) {
|
||||
console.warn(`no dict data of "${dictMeta.type}" found in the response`)
|
||||
return []
|
||||
}
|
||||
return dicts.map(d => dictConverter(d, dictMeta))
|
||||
}
|
||||
|
||||
export function mergeOptions(src) {
|
||||
mergeRecursive(options, src)
|
||||
}
|
||||
|
||||
export default options
|
33
ruoyi-ui/src/utils/dict/index.js
Normal file
33
ruoyi-ui/src/utils/dict/index.js
Normal file
@ -0,0 +1,33 @@
|
||||
import Dict from './Dict'
|
||||
import { mergeOptions } from './DictOptions'
|
||||
|
||||
export default function(Vue, options) {
|
||||
mergeOptions(options)
|
||||
Vue.mixin({
|
||||
data() {
|
||||
if (this.$options.dicts === undefined || this.$options.dicts === null) {
|
||||
return {}
|
||||
}
|
||||
const dict = new Dict()
|
||||
dict.owner = this
|
||||
return {
|
||||
dict
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!(this.dict instanceof Dict)) {
|
||||
return
|
||||
}
|
||||
options.onCreated && options.onCreated(this.dict)
|
||||
this.dict.init(this.$options.dicts).then(() => {
|
||||
options.onReady && options.onReady(this.dict)
|
||||
this.$nextTick(() => {
|
||||
this.$emit('dictReady', this.dict)
|
||||
if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
|
||||
this.$options.methods.onDictReady.call(this, this.dict)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user