前言
对于当下的中后台系统,大部分从事开发的人其实都在对接产品、后端、UI、测试,然后干着 CRUD 的工作。但是如果我们沉淀出一个快速建站框架,这个框架能够通过 DSL 描述一个个模版页,不同的系统需要基于这些模版页去进行配置,那么这个系统 80% 其实都是现成的、可快速搭建的,剩下的 20% 需要自己去定制化开发页面。
正文会用 DSL 描述一个模版页 -> 指示板 dashboard,然后基于系统模型去配置这个模版页进行快速搭建。
下面这张图是整个快速建站框架的架构图。
指示板 dashboard DSL
什么是 DSL
DSL是一种工具,它的核心价值在于,可以更加清晰地就系统某部分的意图进行沟通;是针对某一特定领域,具有受限表达性的一种计算机程序设计语言。
本文使用 json-schema + js 对象去描述一个模版页。
用 DSL 描述 dashboard
头部菜单
最外层 menu 字段描述头部菜单。
菜单就有子菜单,或者直接就是菜单项。这里使用 menuType 进行区分,group 表示有子菜单,可进行递归;module 表示菜单项。
menu: [{
key: '', // 菜单唯一描述
name: '', //菜单名称
menuType: '', // 枚举值,group / module
}]
菜单项
当 menuType 为 module 时,可展示侧边栏 sider、数据页面 schema-view 或者定制化页面 custom-view。
sider 可点击展示侧边栏菜单,菜单配置同头部菜单。
// 当 moduleType == sider 时
siderConfig: {
menu: [{
// 可递归 menuItem (除 moduleType == sider 外)
}, ...]
},
schema-view 可表示各个字段含义,以及在不同组件(表格...)中的作用。
// 当 moduleType == schema 时
schemaConfig: {
api: '', // 数据源 API (遵循 RESTFUL 规范)
schema: { // 板块数据结构
type: 'object',
properties: {
key: {
...schema, // 标准 schema 配置
type: '', // 字段类型
label: '', // 字段的中文名
// 字段在 table 中的相关配置
tableOption: {
...elTableColumnConfig, // 标准 el-table-column 配置
toFixed: 0, // 保留几位小数
visible: true, // 默认为 true (false 时,表示不在表单中显示)
},
},
...
},
required: [], // 必填字段
},
tableConfig: {
rowButtons: [{
label: '', // 按钮中文名
eventKey: '', // 按钮事件名
eventOption: {
// 当 eventKey === 'remove'
params: {
// paramsKey = 参数的键值
// rowValueKey = 参数值 (当格式为 schema::xxx 的时候,到 table 中找响应的字段)
paramKey: rowValueKey
}
}, // 按钮事件具体配置
...elButtonConfig, // 标准 el-button 配置
}, ...],
}, // table 相关配置
}
DSL 总结
{
mode: 'dashboard', // 模板类型,不同模板类型对应不一样的模板数据结构
name: '', // 名词
desc: '', // 描述
icon: '', // icon
homePage: '', // 首页(项目配置)
// 头部菜单
menu: [{
key: '', // 菜单唯一描述
name: '', //菜单名称
menuType: '', // 枚举值,group / module
// 当 menuType == group 时,可填
subMenu: [{
// 可递归 menuItem
}, ...],
// 当 menuType == module 时,可填
moduleType: '', // 枚举值:sider / iframe / custom / schema
// 当 moduleType == sider 时
siderConfig: {
menu: [{
// 可递归 menuItem (除 moduleType == sider 外)
}, ...]
},
// 当 moduleType == custom 时
customConfig: {
path: '', // 自定义路由路径
},
// 当 moduleType == schema 时
schemaConfig: {
api: '', // 数据源 API (遵循 RESTFUL 规范)
schema: { // 板块数据结构
type: 'object',
properties: {
key: {
...schema, // 标准 schema 配置
type: '', // 字段类型
label: '', // 字段的中文名
// 字段在 table 中的相关配置
tableOption: {
...elTableColumnConfig, // 标准 el-table-column 配置
toFixed: 0, // 保留几位小数
visible: true, // 默认为 true (false 时,表示不在表单中显示)
},
},
...
},
required: [], // 必填字段
},
tableConfig: {
rowButtons: [{
label: '', // 按钮中文名
eventKey: '', // 按钮事件名
eventOption: {
// 当 eventKey === 'showComponent',
comName: '', // 组件名称
// 当 eventKey === 'remove'
params: {
// paramsKey = 参数的键值
// rowValueKey = 参数值 (当格式为 schema::xxx 的时候,到 table 中找响应的字段)
paramKey: rowValueKey
}
}, // 按钮事件具体配置
...elButtonConfig, // 标准 el-button 配置
}, ...],
}, // table 相关配置
}
}, ...]
}
领域模型
通过面向对象模式,来作为系统模型生成机制,能快速且灵活地搭建系统模型对象。
不同领域模型有一个基类,然后继承这个基类延伸具体模型。
根据 DSL,配置电商系统基类。
-
头部菜单:商品管理、订单管理和客户管理。
-
商品管理可以配置现成的 schema-view 组件,里面有一个表格,每个字段可以对应表格里面的每一列,操作栏可以配置按钮。(80% 现成的)。
-
订单管理和客户管理可以自定义页面(20% 定制化)。
module.exports = {
model: 'dashboard',
name: '电商系统',
menu: [
{
key: 'product',
name: '商品管理',
menuType: 'module',
moduleType: 'schema',
schemaConfig: {
api: '/api/proj/product',
schema: {
type: 'object',
properties: {
product_id: {
type: 'string',
label: '商品ID',
tableOption: {
width: 300,
'show-overflow-tooltip': true,
},
},
product_name: {
type: 'string',
label: '商品名称',
maxLength: 20,
minLength: 2,
tableOption: {
width: 200,
},
},
price: {
type: 'number',
label: '商品价格',
maximum: 1000,
minimum: 30,
tableOption: {
width: 200,
},
},
inventory: {
type: 'number',
label: '库存',
tableOption: {
width: 200,
},
},
create_time: {
type: 'string',
label: '创建时间',
tableOption: {},
},
},
required: ['product_name'],
},
tableConfig: {
headerButtons: [
{
label: '新增商品',
eventKey: 'showComponent',
eventOption: {
comName: 'createForm',
},
type: 'primary',
plain: true,
},
],
rowButtons: [
{
label: '查看详情',
eventKey: 'showComponent',
eventOption: {
comName: 'detailPanel',
},
type: 'primary',
},
{
label: '修改',
eventKey: 'showComponent',
eventOption: {
comName: 'editForm',
},
type: 'primary',
},
{
label: '删除',
eventKey: 'remove',
type: 'danger',
eventOption: {
params: {
product_id: 'schema::product_id',
},
},
},
],
},
},
},
{
key: 'order',
name: '订单管理',
menuType: 'module',
moduleType: 'custom',
customConfig: {
path: '/todo',
},
},
{
key: 'client',
name: '客户管理',
menuType: 'module',
moduleType: 'custom',
customConfig: {
path: '/todo',
},
},
],
};
根据电商系统基类,延伸不同具体电商系统模型。
继承自上面的基类系统,可以延伸出下面这个电商系统。
- 头部菜单可以拓展出其他菜单(运营活动)或者修改原有菜单项(订单管理)。
- 运营活动可以点击拓展侧边栏菜单,不同侧边菜单栏项可以点击展示不同的组件。
module.exports = {
name: '某宝',
desc: '某宝电商系统',
homePage: '/schema?proj_key=taobao&key=product',
menu: [{
key: 'order',
// iframe 页面
menuType: 'iframe',
iframeConfig: {
path: 'http://www.baidu.com',
},
},{
key: 'operating',
name: '运营活动',
menuType: 'module',
moduleType: 'sider',
siderConfig: {
menu: [{
key: 'coupon',
name: '优惠券',
menuType: 'module',
moduleType: 'custom',
customConfig: {
path: '/todo',
},
},{
key: 'limited',
name: '限量购',
menuType: 'module',
moduleType: 'custom',
customConfig: {
path: '/todo',
},
},{
key: 'festival',
name: '节日活动',
menuType: 'module',
moduleType: 'custom',
customConfig: {
path: '/todo',
},
}]
}
}]
}
总结
- 用 DSL 描述不同模版页,基于面向对象的领域模型结合模版页 DSL 生成具体的系统对象。
- 通过解析器去解析这些系统对象,将解析后的配置放入已写完的模版页,就能生成系统的 80% 的页面。这里需要注意的是解析器只需要写一次,模版页也只需要写一次,后面的相关系统都只需要配置好系统对象,就能快速生成系统,这也是这个快速建站框架的目的。
出处:哲玄大佬的大前端全栈实践,以上是自己的见解和总结。