diff --git a/.fatherrc.js b/.fatherrc.js index 8c6830bd..680c2f30 100644 --- a/.fatherrc.js +++ b/.fatherrc.js @@ -15,6 +15,7 @@ const headPkgs = [ "fes-plugin-layout", "fes-plugin-icon", "fes-plugin-locale", + "fes-plugin-enums", "create-fes-app" ]; const tailPkgs = []; diff --git a/packages/fes-plugin-enums/.fatherrc.js b/packages/fes-plugin-enums/.fatherrc.js new file mode 100644 index 00000000..332f1bff --- /dev/null +++ b/packages/fes-plugin-enums/.fatherrc.js @@ -0,0 +1,3 @@ +export default { + disableTypeCheck: false, +}; diff --git a/packages/fes-plugin-enums/LICENSE b/packages/fes-plugin-enums/LICENSE new file mode 100644 index 00000000..0978fbf7 --- /dev/null +++ b/packages/fes-plugin-enums/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-present webank + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/fes-plugin-enums/README.md b/packages/fes-plugin-enums/README.md new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/packages/fes-plugin-enums/README.md @@ -0,0 +1,2 @@ + + diff --git a/packages/fes-plugin-enums/package.json b/packages/fes-plugin-enums/package.json new file mode 100644 index 00000000..8c96c2b5 --- /dev/null +++ b/packages/fes-plugin-enums/package.json @@ -0,0 +1,33 @@ +{ + "name": "@webank/fes-plugin-enums", + "version": "2.0.0-alpha.2", + "description": "@webank/fes-plugin-enums", + "main": "lib/index.js", + "files": [ + "lib" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/WeBankFinTech/fes.js.git", + "directory": "packages/fes-plugin-enums" + }, + "keywords": [ + "fes" + ], + "author": "aringlai", + "license": "MIT", + "bugs": { + "url": "https://github.com/WeBankFinTech/fes.js/issues" + }, + "homepage": "https://github.com/WeBankFinTech/fes.js#readme", + "publishConfig": { + "access": "public" + }, + "peerDependencies": { + "@webank/fes": "^2.0.0-alpha.0", + "vue": "^3.0.4" + } +} diff --git a/packages/fes-plugin-enums/src/index.js b/packages/fes-plugin-enums/src/index.js new file mode 100644 index 00000000..ec9aec2b --- /dev/null +++ b/packages/fes-plugin-enums/src/index.js @@ -0,0 +1,48 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + +const namespace = 'plugin-enums'; + +export default (api) => { + const { + utils: { Mustache } + } = api; + + api.describe({ + key: 'enums', + config: { + schema(joi) { + return joi.object(); + }, + onChange: api.ConfigChangeType.regenerateTmpFiles + } + }); + + const absoluteFilePath = join(namespace, 'core.js'); + api.onGenerateFiles(() => { + // 文件写出 + const enums = api.config.enums || {}; + api.writeTmpFile({ + path: absoluteFilePath, + content: Mustache.render( + readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'), + { + REPLACE_ENUMS: JSON.stringify(enums) + } + ) + }); + + api.copyTmpFiles({ + namespace, + path: join(__dirname, 'runtime'), + ignore: ['.tpl'] + }); + }); + + api.addPluginExports(() => [ + { + specifiers: ['enums'], + source: absoluteFilePath + } + ]); +}; diff --git a/packages/fes-plugin-enums/src/runtime/core.tpl b/packages/fes-plugin-enums/src/runtime/core.tpl new file mode 100644 index 00000000..e5789ce1 --- /dev/null +++ b/packages/fes-plugin-enums/src/runtime/core.tpl @@ -0,0 +1,176 @@ +import { readonly } from "vue" + +// [[key, value]],默认配置格式 +const _ENUMS = {{{REPLACE_ENUMS}}} +const ENUMS = {} +Object.keys(_ENUMS).forEach(key => { + ENUMS[key] = convert(key, _ENUMS[key]) +}) + +/** + * 获取枚举键值,如不传key,则返回name的枚举数组 + * @param {string} name 枚举名称 + * @param {string} key 枚举键名称 + * @param {{ + * dir: string + * extend: Array<{ + * key:string + * dir:string + * transfer: Function + * }>}} opt 配置项 + */ +function get(name, key, opt = { dir: 'value', extend: []}) { + if (Object.prototype.toString.call(key) === '[object Object]') { + opt = key + key = '' + } + let list = ENUMS[name] || [] + if (key) { + let res = list.filter(item => item.key === key)[0] + if (!res) return key + return readonly(parseValueDir(res.value, opt.dir) || key) + } else { + return readonly(format(list, opt.extend)) + } +} + +/** + * 移除枚举 + * @param {string} name 枚举名称 + */ +function remove(name) { + delete ENUMS[name] +} + +/** + * 添加一个新的枚举,重复添加会覆盖 + * @param {string} name 枚举名称 + * @param {Array} _enum 枚举数组,数组元素可以是数组或者对象 + * @param {object} opt {keyName: 'key', valueName: ''} keyName: 指定枚举键名称取值属性 valueName 指定枚举键值取值属性 + */ +function push(name, _enum, opt = { keyName: '', valueName: '' }) { + if (ENUMS[name]) { + console.warn(`enums warn: the ${name}'s enum already exists, cover!`) + } + ENUMS[name] = convert(name, _enum, opt) + return get(name) +} + +/** + * 基于现有的枚举,连接上新的枚举后返回新的枚举 + * @param {string} name 枚举名称 + * @param {Array} _enum 枚举数组,数组元素可以是数组或者对象 + * @param {{ + * keyName: string, + * valueName: string, + * before: boolean, + * extend: Array<{ + * key: string + * dir: string + * transfer: Function + * }> + * }} opt 配置项,keyName: 指定枚举键名称取值属性 valueName 指定枚举键值取值属性 before: 是否添加在现有的之前 + */ +function concat(name, _enum, opt = { keyName: '', valueName: '', before: false, extend: [] }) { + let list = ENUMS[name] || [] + let partList = convert(name, _enum, opt) || [] + if (opt.before) { + list = partList.concat(list) + } else { + list = list.concat(partList) + } + return readonly(format(list, extend)) +} + +/** + * 格式化枚举 + * @param {Array} _enum 枚举数组 + * @param {Array<{key:string, dir:string, transfer: Function}>} extend 格式化规则 + */ +function format(_enum = [], extend = []) { + if (!extend || extend.length <= 0) return _enum; + return _enum.map(item => { + let _item = {...item} + extend.forEach(fItem => { + if (!fItem.key) return + if (typeof fItem.transfer === 'function') { + _item[fItem.key] = fItem.transfer(item) + } else { + _item[fItem.key] = parseValueDir(item.value, fItem.dir) + } + }) + return _item + }) +} + +/** + * 根据dir解析value的属性值 + * @param value + * @param dir + */ +function parseValueDir(value, dir='value') { + if (['object', 'function'].indexOf(typeof value) || !value || !dir) return value + if (dir.startsWith('[')) { + let key = dir.slice(1, dir.indexOf(']')) + return parseValueDir(value[key], dir.slice(dir.indexOf(']') + 1)) + } else { + if (dir.startsWith('.')) { + dir = dir.slice(1) + } + let index = dir.indexOf('.') + let _index = dir.indexOf('[') + if (index === -1) index = dir.length + if (_index === -1) _index = dir.length + index = Math.min(index, _index) + let key = dir.slice(0, index) + return parseValueDir(value[key], dir.slice(index)) + } +} + +/** + * 转换传入的枚举数组 + * @param {string} name 枚举名称 + * @param {Array} _enum 枚举数组,数组元素可以是数组或者对象 + * @param {{keyName: 'key', valueName: string}} opt keyName: 指定枚举键名称取值属性 valueName 指定枚举键值取值属性 + */ +function convert(name, _enum, opt = { keyName: '', valueName: '' }) { + if (!name) { + throw new Error(`enums error: name must not be empty!`) + } + if (!Array.isArray(_enum)) { + throw new Error(`enums error: the ${name}'s enum must be array!`) + } + let list = [] + _enum.forEach((item, index) => { + let _item; + if (Array.isArray(item)) { + _item = {key: item[0], value: item[1]} + } else if(Object.prototype.toString.call(item) === '[object Object]') { + if (!opt.keyName) opt.keyName = 'key' + // key可能为空,有场景需要使用,比如全选 + _item = { + key: item[opt.keyName], + value: opt.valueName ? item[opt.valueName] : item + } + } else { + console.warn(`enums warn: the key ${name} enum item[${index}] must be array or object!`) + return + } + let res = list.filter(item => item.key === _item.key)[0] + if (res) { // 重复key覆盖提示 + console.warn(`enums warn: the key ${res.key} enum item already exists, cover!`) + res.value = _item.value + } else { + list.push(_item) + } + }) + return list +} + +export const enums = { + get, + push, + remove, + concat, + convert +} \ No newline at end of file diff --git a/packages/fes-template/.fes.js b/packages/fes-template/.fes.js index 328c6dfc..bd048ea3 100644 --- a/packages/fes-template/.fes.js +++ b/packages/fes-template/.fes.js @@ -26,5 +26,8 @@ export default { }, devServer: { port: 8080 + }, + enums: { + status: [['0', '无效的'], ['1', '有效的']] } }; diff --git a/packages/fes-template/package.json b/packages/fes-template/package.json index 1313e09e..21bb99e8 100644 --- a/packages/fes-template/package.json +++ b/packages/fes-template/package.json @@ -48,6 +48,7 @@ "@webank/fes-plugin-layout": "^2.0.0-alpha.0", "@webank/fes-plugin-locale": "^2.0.0-alpha.0", "@webank/fes-plugin-model": "^2.0.0-alpha.0", + "@webank/fes-plugin-enums": "^2.0.0-alpha.0", "ant-design-vue": "2.0.0-rc.3", "vue": "3.0.4" }, diff --git a/packages/fes-template/src/pages/index.vue b/packages/fes-template/src/pages/index.vue index 186149c9..bf40156a 100644 --- a/packages/fes-template/src/pages/index.vue +++ b/packages/fes-template/src/pages/index.vue @@ -5,6 +5,10 @@ accessOnepicess1
accessOnepicess2
+

数据字典

+
{{item.value}}:{{item.key}}
+
{{item.name}}:{{item.disabled}}
+
{{enumsGet('roles', '2', { dir: 'eName' })}}
@@ -16,7 +20,7 @@