简介
其实管理页面的代码生成,现在很多框架都会有,比如若依之类,但是这类框架基本都是和系统是绑定的,并且也只能生成 CRUD
功能。如果你使用自己的后台框架时就不能使用,所以需要一个可以满足任意后端的工具来进行代码的生成与开发
这些框架也只能生成基本功能,只要有点功能出入还是必须手动来编写代码才能完成,这无疑对后端开发者造成很大的困扰,并且效率上也会大打折扣
而各种开源的低代码也绝大多数都是简单的表单设计器,不成体系,解决不了问题
引言
那么如何解决这些问题呢?如何来实现不同规则的接口,不同规则的数据结构,以及自定义的功能的页的自动生成,并且可视化开发定制化的功能
那我们可以将功能拆分:数据库解析(根据数据结构定页面内容),页面母版(生成什么样的页面,是基础 CURD
, 还是独立表单,还是更加复杂的业务),页面的定制(每个页面不一样的功能点,定制化需求),功能的提取(多个页面有存在的重新功能块,如下拉组件选项来自接口)
数据库解析
选择智能创建项目功能后,选择数据库导入,将 mysql
数据库的结构导入(注意:只测试了 navicat
工具导出的结构,如果其它工具导出不行,可以使用数据库连接功能,如果数据库不对口、工具不对口,还可以单个页面生成),主要解析表名,表的注释,字段名,字段的注释,非空,类型等,根据这些信息生成前端的文件名(表名),菜单名(表的注释),组件(字段名,注释,类型,非空),这样就可以解析出一个粗略的模型,那么我们再来看看如何精细的控制,比如页面母版就是用来控制页面功能,操作逻辑,接口调用等等
缺省页面生成
缺省页面母版自然是最简单最不需要理解的 CRUD
母版,但服务端的接口设计需要满足其预设的条件:添加与更新接口是一个接口(服务端根据是否传了主键来自行判断)
自定义页面生成
缺省母版满足不了需求,就需要自定义页面母版了,原理和缺省页面也是相同,先设计出结构与逻辑然后使用
比如一个 CRUD
或者 Form
页面,其实交互逻辑都是相同的,只有里面的元素是不同的,所以只要空出里面的元素,再配合一些变量模版(如每个页面访问的接口应该是变化的)来实现不同的页面之中变化
如果是在 CRUD
功能上扩展或修改,可以复制一个系统自带的 CRUD
母版,然后在此基础上进行修改
如将其原本添加与修改的接口使用的是一个 saveOrUpdate
,修改为两个接口 save
与 update
。所以我们需要先定义两个接口,注意 ${fileName}
变量,是在创建页面的时候的页面名称
然后修改表单提交的事件中判断的代码判断是否有 id
(如果你的后台是用 uid
作为主键,那么应该判断 uid
), 来调用不同的接口
再将原本的删除接口是传的实体对象改为路径,我们修改删除 ${fileName}/remove
为 `` <math xmlns="http://www.w3.org/1998/Math/MathML"> f i l e N a m e / r e m o v e / {fileName}/remove/ </math>fileName/remove/{params.id}, 注意
params是接口入参的固定变量,
id 是你查询接口回来的主键字段名,按需修改如:
<math xmlns="http://www.w3.org/1998/Math/MathML"> f i l e N a m e / r e m o v e / {fileName}/remove/ </math>fileName/remove/{params.uuid}`
再来添加个导出功能,所以定义个导出的接口如 ${fileName}/export
返回类型为 blob
再拖拽个按钮到设计中,处理下点击事件来判定导出逻辑,将多选的 id
与 查询参数传入后端让后端判定如何导出
再添加个批量修改功能等等。。。
接口访问路径
当然不同系统的接口名称定义肯定是存在不一样的,所以将母版里用到的接口在对话交互时应该是可以修改的,如我们将删除接口 ${fileName}/remove
改为:api/${fileName}/delete/${params.id}
,而其它接口前面都加上 api/
, 这样就可以通过简单的修改来应对不同系统的接口定义了
参数变量
什么是参数变量呢,是用来应对不同系统代码块中会不同的地方,比如我们在代码生成的时候有如下调用用户接口成功后处理的片断:
js
userService.search(params).then(res => {
if (res.success) {
setTableData(res.data)
}
})
可以看到判断成功 if(res.success)
这块不同后台返回的可能就是不同的,比如另一个系统是通过状态为零 if(res.code === 0)
这样判断,又或者查询接口的分页参数名等等,这些每个系统可能定义的是不一样的,所以在创建页面母版的时候我们将这些变化的代码块用变量代替,如我们定义:
js
const $temp = {
resSuccess: 'res.success',
pageNo: 'pageNo',
resList: 'res.data.records'
// ...
}
//那么我们不同系统会变化的地方我们什么变量替换
userService.search(params).then(res => {
if ($temp.resSuccess) {
setTableData($temp.resList)
}
})
这样我们就可以将会变化的代码块集中到一块进行处理了,所以在应对不同系统的时候我们只需要修改 $temp
字段对应的值这样将会更加高效
页面配置
这样会根据以上的配置信息去生成单表对应的页面信息,如果有页面用到多张表的字段就修改一下关联的表,注意文件名就是对应上面接口的 ${fileName}
独立页面生成
比如我们数据库不是 mysql
,数据结构解析不了,系统后续添加新表,生成不规则页面(如独立的表单页等)就可以进行单个的页面生成,比如我们可以创建这样一个文本文件(标签名,字段名[, 数据类型(缺省:string)]):
tex
用户名 username
密码 password
年龄 age number
出生日期 birthday date
那么就可以生成相应页面
再删除或者修改一下组件等
开发定制功能
即使是个再简单的系统,也不会全是都是这样标准的 CRUD
,还需要去掉一些功能,再新增一些功能或页面
比如我们需要对数据进行审批
那么在表格中添加个审批按钮,并按状态加载
添加个表单弹窗,配置其 name
属性,再放入需要的组件
处理审批按钮事件,打开表单并将表格行数据传到表单中
添加个审批接口
处理审批表单的事件,将表单的数据通过接口传递到后端,接口调用中使提交按钮加载中,接口调用结束后关闭弹窗,重新查询下数据
添加个一对多新表单页面
页面不在路由展示,通过按钮跳转到此页面
放入一个表单,再放入一个表格。。。
添加个菜单权限功能
我们在用户管理中添加个 treeselect
组件,把options
设置为页面菜单
等等,按需求进行功能定制即可
模块
一个系统多个页面之中总会有重复的组件(如远程获取公司名称的 Select
),或连续的A+B+C组件(用户名,手手机号,开始日期)
这种情况可以将此类变成模块,而可以快速应用到其他页面之中,从而拒绝重复开发
代码生成与启动
而设计器对应的其实就是一个JSON
,那么我们就需要解析这个JSON
来生成需要的 React
或者 Vue
代码即可
js
//JSON
[
{
type: 'Search',
data: {},
children: [
{type: 'input', data: {}, ...},
[
{type: 'button', data: {}, ...},
{type: 'button', data: {}, ...},
{type: 'space', data: {}, ...}
]
]
},
{
type: 'Region',
data: {},
...
}
]
我们先准备好一个脚手架,我们再将这样一个 JSON
遍历,将对应 type
变成组件等等,形成一个个页面文件输入到脚手架对应文件夹内,从而生成完整的项目。
下载到本地安装依赖 npm i
,然后启动项目 npm start
即可完成完整流程,再或者打包发布 npm run build
总结
这样设计的一个工具,对于中小型简单的管理页面,服务端开发人员即使不会前端,也可以轻松在一小时内完成各类系统,而不需要手动编写前端代码。而对于功能很复杂的系统如果会些前端知识也可以十倍效率于手工了
工具是一个不断改进的过程产物,无法一步到位,但有很大可能性来加快我们前进的脚步
只有敢于尝试,不害怕失败,并在不断实践中才能找到新的突破
具体功能可以借鉴:Light2f 中后台前端可视化开发工具
希望更多的小伙伴能找到的思路,有更多的思考,有更多的创新,而不只拘泥于学习