概述
基于领域模型概念设计了一套配置驱动的DSL(Domain Specific Language)模板配置系统 ,通过JSON Schema(核心)配置文件驱动页面生成,实现了高度可配置化的管理系统。该架构采用模型-项目继承设计,支持多项目、多领域的复杂业务场景,有效解决了传统前端开发中的70-80%的重复性工作和维护难题。
一、核心设计理念
1.1 配置驱动开发
通过一套标准化的配置数据即可驱动生成整个站点的页面组件,将"手写代码"转变为"配置生成",大幅提升开发效率。
1.2 模型继承机制
基础模型配置可被多个项目继承和扩展(设计灵感来源于面向对象思维),支持内容沉淀的同时保持可定制化灵活性,遵循DRY (Don't repeat yourself) 原则。
1.3 组件化架构
基于Vue 3的响应式组件化架构,支持动态组件渲染和组合,确保良好的可维护性和扩展性。
1.4 领域分离
按业务领域组织模型配置,不同领域可派生出对应的项目类型,保持业务逻辑的清晰分离。
二、解决的核心痛点
2.1 重复性CRUD开发
传统痛点:每个业务模块都需要重复编写表格、搜索、增删改查的代码,而实际上的区别大多数情况下都是字段和数据源不同。
解决方案:通过对 JSON Schema 进行拓展,使其可用于配置自动生成完整的CRUD界面
JSON
// Schema 配置设计模板
schemaConfig: {
api: '', //数据源api (遵循 RESTFUL 规范)
schema: { // 模板数据结构
type: 'object',
properties: {
key: {
...schema, // 标准的 json schema 配置
type: "", // 字段类型
label: '', // 字段的中文名
//对应字段在 table 中的相关配置
tableOption: {
...elTableConfigColumn, // 标准的el-table-column 配置内容
visible: true, // 默认为true, (false或不配置的时候,表示不在表单中显示)
..., //可自行设计对数据处理的配置,如:toFixed:2 小数表示保留两位;
},
// 字段在search-bar 中的相关配置
searchOption: {
...eleComponentConfig, // 标准的 el-component-config 配置
comType: '', // 配置组件类型 input select ...
default: '', // 默认值,
..., //可拓展,不同组件类型 对应的配置设计
},
...,// 可拓展,表单配置 formOption ...
},
...
},
},
// table 相关配置,
tableConfig: {
headerButtons: [
...,
],
// 表格中每行按钮设计
rowButtons: [
{
label: '',//按钮中文名称
eventKey: '', // 按钮事件名
// 按钮事件具体配置
eventOption: {
...
},
...elButtonOption, //标准el-button 配置
},
...
]
},
searchConfig: {}, // search-bar 搜索框相关配置,
components: {}, // 模块组件
},
2.2 组件复用困难
传统痛点:不同页面的表格、搜索组件功能差异大,难以复用
解决方案:通过tableOption、searchOption等标准化配置实现组件的灵活定制
2.3 状态管理复杂
传统痛点:搜索条件、分页状态、选中状态需要手动管理
解决方案:自动处理URL参数与搜索默认值的映射,实现状态持久化; 如:给keyword字段添加默认值 url:xxx/xxx?keyword=默认值
三、架构设计
四、核心技术实现
4.1 配置继承机制
js
model/
├── business/ # 电商领域
│ ├── model.js # 基础模型配置
│ └── project/ # 具体项目配置
│ ├── pdd.js # 拼多多项目
│ ├── jd.js # 京东项目
│ └── taobao.js # 淘宝项目
├── course/ # 课程领域
│ ├── model.js # 基础模型配置
│ └── project/ # 具体项目配置
│ ├── bilibili.js # B站项目
│ └── douyin.js # 抖音项目
└── index.js # 模型加载器
// 实际案例:
/**
* 项目继承model
* @param {object} model model 配置
* @param {object} project project 配置
* @returns {object} 继承后的 project 配置
*
*/
const projectExtendModel = (model, project) => {
return _.mergeWith({}, model, project, (modelVal, projVal) => {
// 处理数组合并的特殊情况
if (Array.isArray(modelVal) && Array.isArray(projVal)) {
let result = [];
// 因为project 继承 model , 所以需要处理修改和新增内容的情况
// 情况一 project 有的键值, model 也有 则为 修改 (重载)
// 情况二 project 有的键值, model 没有 则为 新增 (拓展)
// 情况三 project 没有的键值, model 有 则为 保留 (继承)
for (let i = 0; i < modelVal.length; ++i) {
const modelItem = modelVal[i];
const projItem = projVal.find(item => item.key === modelItem.key);
// 情况一 修改 情况三 继承
result.push(projItem ? projectExtendModel(modelItem, projItem) : modelItem)
}
for (let i = 0; i < projVal.length; ++i) {
const projItem = projVal[i];
const modelItem = modelVal.find(item => item.key === projItem.key);
// 情况二 新增
if (!modelItem) {
result.push(projItem)
}
}
return result;
}
})
}
4.2 动态组件渲染
Schema配置解析
通过schema.js实现配置数据的智能解析和转换:
js
// 基础模型 (model/business/model.js)
menu: [
{
key: 'product',
name: '商品管理',
schemaConfig:{
...,// 基础配置
}
},
]
//项目配置(model/business/project/pdd.js)
name: '拼多多',
menu: [
{
key: 'product',
name: '商品管理(拼多多)'
},
{
key: 'client',
name: '客户管理(拼多多)'
},
]
SchemaOption的清洗和过滤
为了在渲染时,把保留对应组件的相关配置,剔除无用的配置,需要进行以下的处理:
js
// 通用构建schema 方法 (消除噪音)
const buildDtoSchema = (_schema, comName) => {
if (!_schema?.properties) return
const dtoSchema = {
type: 'object',
properties: {}
}
//提取有效 schema 字段信息
for (const key in _schema.properties) {
const props = _schema.properties[key]
// tableOption searchBarOption formOption
if (props[`${comName}Option`]) {
let dtoProps = {};
// 提取 props 中 非option的部分 存放到dtoProps中
for (const pKey in props) {
if (pKey.indexOf('Option') < 0) {
dtoProps[pKey] = props[pKey]
}
}
// 处理conName Option
dtoProps = Object.assign({}, dtoProps, { option: props[`${comName}Option`] });
dtoSchema.properties[key] = dtoProps;
}
}
return dtoSchema
}
4.3 路由和视图管理
视图组件架构
-
header-view: 头部菜单渲染,支持项目切换和多级菜单
-
sider-view: 侧边栏复合视图,支持嵌套路由和默认选中
-
schema-view: 配置驱动的CRUD页面核心组件
-
iframe-view: 外部页面嵌入支持
4.4 Schema 配置解析于数据流转
动态组件注册
js
//组件配置映射
const SearchItemConfig = {
input: {
component: Input
},
select: {
component: Select
},
dynamicSelect: {
component: DynamicSelect
},
dateRange: {
component: DateRange
},
...,//后续组件拓展可在此处进行,无需修改核心代码,只需扩展配置
}
// 动态组件渲染
<component
:is="SearchItemConfig[schemaItem.option?.comType]?.component"
:ref="handleSearchComList"
:schema-key="key"
:schema="schemaItem"
@loaded="handleChildLoaded"
/>
4.5 数据请求与状态管理流程

五、实践案例与效果展示
5.1 多项目配置继承实例
以拼多多项目为例,展示完整的配置继承效果:

5.2 实际配置效果对比
一份配置,多端复用:
js
// 同一份商品配置,在不同项目中的表现
// 淘宝项目:展示"淘宝商品管理"
// 京东项目:展示"京东商品管理"
// 拼多多项目:展示"拼多多商品管理" + 额外的客户管理功能
总结
这套基于配置驱动的DSL架构通过以下核心实现:
-
配置即代码:将70-80%的重复性开发工作转化为配置编写
-
模型继承:基于面向对象思维的继承机制
-
组件化:高度解耦的动态组件渲染系统
-
标准化:基于JSON Schema的标准配置进行拓展的规范