大部分业务系统、管理后台 70% 的功能是数据表格的增删改查。这些功能的实现,以复制粘贴修改字段为主。本文将尝试用一种更优雅的 “复制粘贴” 方式编写此类功能。如果你希望告别枯燥乏味的重复劳动,或者需要自建一套云表格系统,接下来的内容可以帮到你。
通过表格编辑器,在线设计制作表格类功能模块。适用于用户管理、供应商管理、订单管理等表格 CURD 操作的功能模块。
源码地址: https://github.com/YaoApp/demo-widget
一键部署: https://letsinfra.com/openapp/demo-widget
YAO 是一款开源应用引擎,使用 Golang 编写,以一个命令行工具的形式存在, 下载即用。适合用于搭建业务系统、网站/APP API 接口、管理后台等应用程序。
YAO 采用 flow-based 的编程模式,通过编写 YAO DSL (JSON 格式逻辑描述) 或 JavaScript 处理器,实现各种功能。 YAO DSL 可以有多种编写方式:
GitHub 地址: https://github.com/yaoapp/yao
Github Stars: 4.3K
开源协议: Apache 2.0
官方文档: https://yaoapps.com/doc
YAO 将通用功能模块抽象为 Widget,通过 YAO DSL 描述差异,快速复制各种功能。 在开发中,如果开发一个相似的功能模块,需要将已有的功能复制粘贴,批量替换差异内容。 YAO 提供一种新方式 ,使用 DSL 描述差异内容,快速“复制粘贴”一个功能模块,以此来提升开发效率。
YAO 内建了一组 Widgets, 涵盖大部分应用程序开发常见功能。
内建 Widget | 功能 |
---|---|
model | 数据结构建模 |
flow | 数据逻辑编排 |
api | RESTFul API |
table | 表格 CURD |
chart | 数据图表 |
login | 用户登录 |
register | 用户注册 |
task | 并发任务 |
schedule | 计划任务 |
socket | Socket |
websocket | WebSocket |
Widget 支持开发者自定义,可基于自身业务逻辑特征,自定义 DSL, 快速复制各种通用功能。本文将通过自定义 Widget 的方式,实现一套云表格系统。
阅读以下内容,需要具备基础编程能力,熟悉 RESTFul API ,关系数据库,JavaScript 语言等编程常识。
参考文档 入门指南 , 在本地安装 YAO 命令 ( 版本: v0.10.1),并熟悉基本使用方法。
在本地创建一个应用:
# 创建一个项目文件夹mkdir -p /your/project/root# 初始化项目yao init# 创建数据表 & 初始化菜单yao migrate && yao run flows.setmenu
根据业务逻辑特征,设计 DSL 结构,本例中,不同表格间的差异为 表格字段、搜索器以及表格名称。 dyform Widget DSL 数据结构:
{"name": "TEST","decription": "A TEST DYFORM","columns": [{"title": "First Name","name": "name","type": "input","search": true,"props": {"placeholder": "Please input your first name"}},{"title": "Amount","name": "amount","type": "input","search": true,"props": {"placeholder": "Please input amount"}},{"title": "Description","name": "desc","type": "textArea","props": {"placeholder": "Please input Description"}}]}
字段描述 DSL :
配置项 | 说明 |
---|---|
title | 在表格中显示的标题 |
name | 字段名称, 对应数据库字段名 |
type | 填写表单时,使用的组件 |
props | 组件属性 |
search | 该字段是否可以作为筛查项 |
创建 dyforms 文件,用于保存 DSL
cd /your/project/rootmkdir dyforms
将上面 DSL 保存到 dyforms/demo.form.yao 文件,用于调试。
创建 dyform widget:
cd /your/project/rootmkdir -p widgets/dyform# 创建 widget 文件touch widgets/dyform/widget.json # Widget 基本信息touch widgets/dyform/compile.js # dyform DSL 编译器touch widgets/dyform/process.js # dyform 处理器touch widgets/dyform/export.js # dyform 导出内建 Widget 定义
提示: YAO 自定义 widget 放置在 widgets 目录,需要手动创建这个目录。
使用编辑器打开 dyform/widget.json 填写 dyform widget 基本信息
{"label": "Dynamic Form","description": "A form widget. users can design forms online","version": "0.1.0","root": "dyforms","extension": ".form.yao","modules": ["Models", "Tables"]}
字段说明:
配置项 | 说明 |
---|---|
label | Widget 名称,在可视化编辑器显示。 |
description | Widget 介绍, 在可视化编辑器显示。 |
version | 版本号 |
root | DSL 文件保存路径(相对于项目根目录) |
extension | DSL 文件扩展名 |
modules | 需要导出的模块。 在 export.js 中根据 DSL 描述,转换的 YAO 内建 widgets。 如 model, table 等。这些 widgets 与保存在项目目录中的 DSL 文件等效。 |
编写 dyform/process.js 脚本,实现 Model, Table 处理器,将自定义 DSL 转换为 YAO 数据模型 widget 和 表格 widget。
编写 Export 函数,声明要导出的处理器, 查看源码
function Export() {return { Model: "Model", Table: "Table" };}
实现 Model & Table 处理器逻辑
处理器 | 说明 | 源码链接 |
---|---|---|
Model | 将 dyform DSL 转换为 model DSL, 等效于在 models 文件夹手动编写一个 xxx.mod.yao DSL 文件 | 查看源码 |
Table | 将 dyform DSL 转换为 table DSL, 等效于在 tables 文件夹手动编写一个 xxx..json DSL 文件 | 查看源码 |
提示: 建议使用 yao run 命令调试处理器,参考源码注释文档。
编写 dyform/export.js 脚本, 实现 Models, Tables 函数,导出为 YAO model & table widgets.
导出函数 | 说明 | 源码链接 |
---|---|---|
Models | 调用 Model 处理器,导出 Yao model widget, 数据结构为 {MODEL_NAME:String: Model_DSL:Object} | 查看源码 |
Tables | 调用 Table 处理器, 导出为 Yao table widget , 数据结构为: {TABLE_NAME:String: Table_DSL:Object} | 查看源码 |
在 dyforms 文件夹下,添加 xxx.form.yao 文件, 编写 dyform DSL 描述文件,即可快速创建一组表格管理模块、表格 API、表格处理器和模型处理器。
使用 yao migrate 命令创建数据表结构,yao start 命令启动服务,登录管理界面,即可使用表格管理功能。 路由地址: http://127.0.0.1:5099/xiang/table/dyform.xxx
如果希望把表格制作功能开放给用户,且在通常情况下代码目录应设定为只读,这就无法动态创建 DSL 文件。对 dyform widget 稍加改造,将 dyform DSL 保存在数据库中即可。
如何创建使用数据模型 models/template.mod.yao 和管理表格 tables/template.tab.yao, 参考Model 文档 和 Table 文档 models/template.mod.yao 如下
{"name": "Template","table": { "name": "template", "comment": "For dyform DSL source" },"columns": [{ "label": "ID", "name": "id", "type": "ID", "comment": "ID" },{ "label": "Name", "name": "name", "type": "string", "index": true },{"label": "DSL","name": "dsl","type": "text","comment": "DSL"}],"values": [],"option": { "timestamps": true, "soft_deletes": true }}
DSL 管理界面
编写 Export 函数,声明要导出的处理器, 查看源码
function Export() {return { Model: "Model", Table: "Table", Save: "Save", Delete: "Delete" };}
实现 Save & Delete 处理器逻辑
处理器 | 说明 | 源码链接 |
---|---|---|
Save | 根据 dyform DSL 转换为 model DSL, 更新对应数据模型结构,同时重新加载对应实例。 | 查看源码 |
Delete | 删除数据模型对应数据表 | 查看源码 |
编辑 tables/template.tab.yao,添加 hooks 脚本,在表格保存和删除时,更新/删除数据表,创建/删除菜单。
修改 tables/template.tab.yao 添加 Hook 查看源码** **
"hooks": {"after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"},
添加 hooks 脚本 scripts/template.js 查看源码
Hook | 说明 |
---|---|
AfterSave | 根据 DSL ,更新 dyform 数据表,并添加菜单 |
Delete | 删除 dyform 数据表,并移除菜单 |
编辑 widgets/dyform/compile.js , 从数据库中读取 DSL
/*** Source* Where to get the source of DSL*/function Source() {var sources = {};tpls = Process("models.template.Get", { select: ["id", "dsl"], limit: 1000 });if (tpls.code && tpls.message) {log.Error("Load dyform sources: %s", tpls.message);return sources;}tpls.forEach((tpl) => {tpl = tpl || {};try {instance = `instance_${tpl.id}`;dsl = JSON.parse(tpl.dsl);sources[instance] = dsl;} catch (e) {log.Error("Source %v DSL: %s", tpl.id, e.message);return;}});return sources;}
Compile.js 方法说明 查看文档
Hook | 说明 |
---|---|
Source | 自定义 DSL 数据源读取逻辑 |
Compile | 根据上下文或环境信息,调整 DSL 结构或准备相关资源 |
OnLoad | 当 DSL 加载完成,调用此方法。 |
登录管理后台,动态添加 dyform DSL ,即可动态创建删除对应表格。
可以使用表单制作工具来生成 form DSL。有很多优秀的开源表单编辑器可以选择,比如 XXXX , 为了演示效果,XGEN 快速实现了一个 DEMO 级的编辑器组件,产品级的实现将在 XGEN-NEXT (正式版) 发布时提供。 源码地址: https://github.com/YaoApp/xgen/tree/main/src/cloud/components/form/FormPrinter
为 template 表格添加 Hook, 用来转换 DSL 结构。 编辑 tables/template.tab.yao
文件、 scripts/template.js
文件
添加 **before:save**
hook
将编辑器组件输出,转换为 form DSL
tables/template.tab.yao
{..."hooks": {"before:save": "scripts.template.BeforeSave","after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"}...}
scripts/template.js
/*** BeforSave Hook: transform the form editor data to the DSL* @param {*} payload*/function BeforeSave(payload) {payload = payload || {};columns = payload.dsl || [];payload["dsl"] = { columns: [], name: payload.name || "UNTITLE" };columns.forEach((column) => {let type = column.id || "";payload["dsl"].columns.push({title: column.title || "UNTITLE",name: column.bind,type: type.toLowerCase(),props: column.props || {},});});payload["dsl"] = JSON.stringify(payload["dsl"]);return [payload];}
tips : 可是使用 yao run
命令调试例如:
yao run scripts.template.BeforeSave '::{"dsl":...}'
添加 **after:find**
hook
将 form DSL 转换为组件输入结构
tables/template.tab.yao
{..."hooks": {"after:find": "scripts.template.AfterFind","before:save": "scripts.template.BeforeSave","after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"}...}
scripts/template.js
/*** AfterFind Hook: transform the DSL format to the form editor needs* @param {*} id* @param {*} template*/function AfterFind(template, id) {let dsl = JSON.parse(template["dsl"]);let columns = dsl.columns || [];let types = { input: "Input", select: "Select" };template["dsl"] = [];columns.forEach((column) => {// let props = column.props || {};// let search = props.showSearch ? true : false;template["dsl"].push({title: column.title,bind: column.name,id: types[column.type],props: column.props || {},search: true,width: 6,chosen: false,selected: false,});});return template;}
编辑 tables/template.tab.yao
文件, 将 DSL 字段编辑组件设定为 FormPrinter。
源码地址: https://github.com/YaoApp/demo-widget/blob/main/tables/template.tab.yao
{...."Form Editor": {"label": "Form Editor","edit": { "type": "FormPrinter", "props": { "value": ":dsl" } }}...}
打开 templates 表格,点击编辑一个模板,即可使用可视化编辑器制作表单。
对于活动报名、预约注册等 C 端页面,需要个性化设计来提升用户体验。对于此类场景,可以有针对性的设计一组模板,使用任意前端技术栈实现。这里提供一个 VUE3 实现的 DEMO。 源码地址: https://github.com/YaoApp/demo-widget-front
添加一个 GET /page/form/setting/:name
API , 在 apis 文件夹下,添加一个 page.http.json 文件, 添加一个接口,第一个参数为 表格名称.
{"name": "Table Setting","version": "1.0.0","description": "Table Setting","group": "page","guard": "-","paths": [{"path": "/form/setting/:name","method": "GET","guard": "-","process": "xiang.table.Setting","in": ["$param.name", ":query"],"out": { "status": 200, "type": "application/json" }}]}
源码地址: https://github.com/YaoApp/demo-widget/blob/main/apis/page.http.json
const url = `${window.location.protocol}//${window.location.host}/api/page/form/setting/${formName}`;const response = fetch(url);response.then((res) => {return res.json();}).then((data) => {formTitle.value = data.name;const fieldset = data?.edit?.layout?.fieldset || [];const columns = fieldset.length > 0 ? fieldset[0]?.columns : [];const mapping = data?.columns || {};columns.forEach((col: any) => {let column = mapping[col.name] || false;if (column?.edit) {let name = column.edit.props?.value || "";column.edit.label = col.name;column.edit.field = name.replace(":", "");column.edit.type = components[column.edit.type];formItems.value.push(column.edit);}});loading.value = true;}).catch((err) => {console.log("ERR", err);failure.value = err.message;});
源码地址: https://github.com/YaoApp/demo-widget-front/blob/main/vue3/src/App.vue
使用 component
组件,根据配置渲染表单
<template><div v-if="loading"><div class="header">{{ formTitle }}</div><form><div class="form-item" v-for="item of formItems" :key="item.label"><div class="label">{{ item.label }}</div><component :is="item.type" :name="item.field"></component></div><div class="form-item" v-if="formItems"><button class="button" type="button">Submit</button></div></form></div><div v-else-if="failure" class="failure">{{ failure }}</div><div v-else><div>Loading...</div></div></template>
源码地址: https://github.com/YaoApp/demo-widget-front/blob/main/vue3/src/App.vue
YAO 内建了一个 HTTP server,将制品复制到 ui 目录即可访问
npm run buildcp -r dist ../demo-widget/ui/vue3
源码地址: https://github.com/YaoApp/demo-widget/tree/main/ui/vue3
打开浏览器,输入 http://your-host:port/xiang/login/admin
进入后台,录入并保存一个表单。
默认用户名: xiang@iqka.com
默认密码: A123456p+
打开 http://your-host:port/vue3/?form=dyform.instance_1
即可访问自定义表单页面
大部分业务系统、管理后台 70% 的功能是数据表格的增删改查。这些功能的实现,以复制粘贴修改字段为主。本文将尝试用一种更优雅的 “复制粘贴” 方式编写此类功能。如果你希望告别枯燥乏味的重复劳动,或者需要自建一套云表格系统,接下来的内容可以帮到你。
通过表格编辑器,在线设计制作表格类功能模块。适用于用户管理、供应商管理、订单管理等表格 CURD 操作的功能模块。
源码地址: https://github.com/YaoApp/demo-widget
一键部署: https://letsinfra.com/openapp/demo-widget
YAO 是一款开源应用引擎,使用 Golang 编写,以一个命令行工具的形式存在, 下载即用。适合用于搭建业务系统、网站/APP API 接口、管理后台等应用程序。
YAO 采用 flow-based 的编程模式,通过编写 YAO DSL (JSON 格式逻辑描述) 或 JavaScript 处理器,实现各种功能。 YAO DSL 可以有多种编写方式:
GitHub 地址: https://github.com/yaoapp/yao
Github Stars: 4.3K
开源协议: Apache 2.0
官方文档: https://yaoapps.com/doc
YAO 将通用功能模块抽象为 Widget,通过 YAO DSL 描述差异,快速复制各种功能。 在开发中,如果开发一个相似的功能模块,需要将已有的功能复制粘贴,批量替换差异内容。 YAO 提供一种新方式 ,使用 DSL 描述差异内容,快速“复制粘贴”一个功能模块,以此来提升开发效率。
YAO 内建了一组 Widgets, 涵盖大部分应用程序开发常见功能。
内建 Widget | 功能 |
---|---|
model | 数据结构建模 |
flow | 数据逻辑编排 |
api | RESTFul API |
table | 表格 CURD |
chart | 数据图表 |
login | 用户登录 |
register | 用户注册 |
task | 并发任务 |
schedule | 计划任务 |
socket | Socket |
websocket | WebSocket |
Widget 支持开发者自定义,可基于自身业务逻辑特征,自定义 DSL, 快速复制各种通用功能。本文将通过自定义 Widget 的方式,实现一套云表格系统。
阅读以下内容,需要具备基础编程能力,熟悉 RESTFul API ,关系数据库,JavaScript 语言等编程常识。
参考文档 入门指南 , 在本地安装 YAO 命令 ( 版本: v0.10.1),并熟悉基本使用方法。
在本地创建一个应用:
# 创建一个项目文件夹mkdir -p /your/project/root# 初始化项目yao init# 创建数据表 & 初始化菜单yao migrate && yao run flows.setmenu
根据业务逻辑特征,设计 DSL 结构,本例中,不同表格间的差异为 表格字段、搜索器以及表格名称。 dyform Widget DSL 数据结构:
{"name": "TEST","decription": "A TEST DYFORM","columns": [{"title": "First Name","name": "name","type": "input","search": true,"props": {"placeholder": "Please input your first name"}},{"title": "Amount","name": "amount","type": "input","search": true,"props": {"placeholder": "Please input amount"}},{"title": "Description","name": "desc","type": "textArea","props": {"placeholder": "Please input Description"}}]}
字段描述 DSL :
配置项 | 说明 |
---|---|
title | 在表格中显示的标题 |
name | 字段名称, 对应数据库字段名 |
type | 填写表单时,使用的组件 |
props | 组件属性 |
search | 该字段是否可以作为筛查项 |
创建 dyforms 文件,用于保存 DSL
cd /your/project/rootmkdir dyforms
将上面 DSL 保存到 dyforms/demo.form.yao 文件,用于调试。
创建 dyform widget:
cd /your/project/rootmkdir -p widgets/dyform# 创建 widget 文件touch widgets/dyform/widget.json # Widget 基本信息touch widgets/dyform/compile.js # dyform DSL 编译器touch widgets/dyform/process.js # dyform 处理器touch widgets/dyform/export.js # dyform 导出内建 Widget 定义
提示: YAO 自定义 widget 放置在 widgets 目录,需要手动创建这个目录。
使用编辑器打开 dyform/widget.json 填写 dyform widget 基本信息
{"label": "Dynamic Form","description": "A form widget. users can design forms online","version": "0.1.0","root": "dyforms","extension": ".form.yao","modules": ["Models", "Tables"]}
字段说明:
配置项 | 说明 |
---|---|
label | Widget 名称,在可视化编辑器显示。 |
description | Widget 介绍, 在可视化编辑器显示。 |
version | 版本号 |
root | DSL 文件保存路径(相对于项目根目录) |
extension | DSL 文件扩展名 |
modules | 需要导出的模块。 在 export.js 中根据 DSL 描述,转换的 YAO 内建 widgets。 如 model, table 等。这些 widgets 与保存在项目目录中的 DSL 文件等效。 |
编写 dyform/process.js 脚本,实现 Model, Table 处理器,将自定义 DSL 转换为 YAO 数据模型 widget 和 表格 widget。
编写 Export 函数,声明要导出的处理器, 查看源码
function Export() {return { Model: "Model", Table: "Table" };}
实现 Model & Table 处理器逻辑
处理器 | 说明 | 源码链接 |
---|---|---|
Model | 将 dyform DSL 转换为 model DSL, 等效于在 models 文件夹手动编写一个 xxx.mod.yao DSL 文件 | 查看源码 |
Table | 将 dyform DSL 转换为 table DSL, 等效于在 tables 文件夹手动编写一个 xxx..json DSL 文件 | 查看源码 |
提示: 建议使用 yao run 命令调试处理器,参考源码注释文档。
编写 dyform/export.js 脚本, 实现 Models, Tables 函数,导出为 YAO model & table widgets.
导出函数 | 说明 | 源码链接 |
---|---|---|
Models | 调用 Model 处理器,导出 Yao model widget, 数据结构为 {MODEL_NAME:String: Model_DSL:Object} | 查看源码 |
Tables | 调用 Table 处理器, 导出为 Yao table widget , 数据结构为: {TABLE_NAME:String: Table_DSL:Object} | 查看源码 |
在 dyforms 文件夹下,添加 xxx.form.yao 文件, 编写 dyform DSL 描述文件,即可快速创建一组表格管理模块、表格 API、表格处理器和模型处理器。
使用 yao migrate 命令创建数据表结构,yao start 命令启动服务,登录管理界面,即可使用表格管理功能。 路由地址: http://127.0.0.1:5099/xiang/table/dyform.xxx
如果希望把表格制作功能开放给用户,且在通常情况下代码目录应设定为只读,这就无法动态创建 DSL 文件。对 dyform widget 稍加改造,将 dyform DSL 保存在数据库中即可。
如何创建使用数据模型 models/template.mod.yao 和管理表格 tables/template.tab.yao, 参考Model 文档 和 Table 文档 models/template.mod.yao 如下
{"name": "Template","table": { "name": "template", "comment": "For dyform DSL source" },"columns": [{ "label": "ID", "name": "id", "type": "ID", "comment": "ID" },{ "label": "Name", "name": "name", "type": "string", "index": true },{"label": "DSL","name": "dsl","type": "text","comment": "DSL"}],"values": [],"option": { "timestamps": true, "soft_deletes": true }}
DSL 管理界面
编写 Export 函数,声明要导出的处理器, 查看源码
function Export() {return { Model: "Model", Table: "Table", Save: "Save", Delete: "Delete" };}
实现 Save & Delete 处理器逻辑
处理器 | 说明 | 源码链接 |
---|---|---|
Save | 根据 dyform DSL 转换为 model DSL, 更新对应数据模型结构,同时重新加载对应实例。 | 查看源码 |
Delete | 删除数据模型对应数据表 | 查看源码 |
编辑 tables/template.tab.yao,添加 hooks 脚本,在表格保存和删除时,更新/删除数据表,创建/删除菜单。
修改 tables/template.tab.yao 添加 Hook 查看源码** **
"hooks": {"after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"},
添加 hooks 脚本 scripts/template.js 查看源码
Hook | 说明 |
---|---|
AfterSave | 根据 DSL ,更新 dyform 数据表,并添加菜单 |
Delete | 删除 dyform 数据表,并移除菜单 |
编辑 widgets/dyform/compile.js , 从数据库中读取 DSL
/*** Source* Where to get the source of DSL*/function Source() {var sources = {};tpls = Process("models.template.Get", { select: ["id", "dsl"], limit: 1000 });if (tpls.code && tpls.message) {log.Error("Load dyform sources: %s", tpls.message);return sources;}tpls.forEach((tpl) => {tpl = tpl || {};try {instance = `instance_${tpl.id}`;dsl = JSON.parse(tpl.dsl);sources[instance] = dsl;} catch (e) {log.Error("Source %v DSL: %s", tpl.id, e.message);return;}});return sources;}
Compile.js 方法说明 查看文档
Hook | 说明 |
---|---|
Source | 自定义 DSL 数据源读取逻辑 |
Compile | 根据上下文或环境信息,调整 DSL 结构或准备相关资源 |
OnLoad | 当 DSL 加载完成,调用此方法。 |
登录管理后台,动态添加 dyform DSL ,即可动态创建删除对应表格。
可以使用表单制作工具来生成 form DSL。有很多优秀的开源表单编辑器可以选择,比如 XXXX , 为了演示效果,XGEN 快速实现了一个 DEMO 级的编辑器组件,产品级的实现将在 XGEN-NEXT (正式版) 发布时提供。 源码地址: https://github.com/YaoApp/xgen/tree/main/src/cloud/components/form/FormPrinter
为 template 表格添加 Hook, 用来转换 DSL 结构。 编辑 tables/template.tab.yao
文件、 scripts/template.js
文件
添加 **before:save**
hook
将编辑器组件输出,转换为 form DSL
tables/template.tab.yao
{..."hooks": {"before:save": "scripts.template.BeforeSave","after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"}...}
scripts/template.js
/*** BeforSave Hook: transform the form editor data to the DSL* @param {*} payload*/function BeforeSave(payload) {payload = payload || {};columns = payload.dsl || [];payload["dsl"] = { columns: [], name: payload.name || "UNTITLE" };columns.forEach((column) => {let type = column.id || "";payload["dsl"].columns.push({title: column.title || "UNTITLE",name: column.bind,type: type.toLowerCase(),props: column.props || {},});});payload["dsl"] = JSON.stringify(payload["dsl"]);return [payload];}
tips : 可是使用 yao run
命令调试例如:
yao run scripts.template.BeforeSave '::{"dsl":...}'
添加 **after:find**
hook
将 form DSL 转换为组件输入结构
tables/template.tab.yao
{..."hooks": {"after:find": "scripts.template.AfterFind","before:save": "scripts.template.BeforeSave","after:save": "scripts.template.AfterSave","after:delete": "scripts.template.AfterDelete"}...}
scripts/template.js
/*** AfterFind Hook: transform the DSL format to the form editor needs* @param {*} id* @param {*} template*/function AfterFind(template, id) {let dsl = JSON.parse(template["dsl"]);let columns = dsl.columns || [];let types = { input: "Input", select: "Select" };template["dsl"] = [];columns.forEach((column) => {// let props = column.props || {};// let search = props.showSearch ? true : false;template["dsl"].push({title: column.title,bind: column.name,id: types[column.type],props: column.props || {},search: true,width: 6,chosen: false,selected: false,});});return template;}
编辑 tables/template.tab.yao
文件, 将 DSL 字段编辑组件设定为 FormPrinter。
源码地址: https://github.com/YaoApp/demo-widget/blob/main/tables/template.tab.yao
{...."Form Editor": {"label": "Form Editor","edit": { "type": "FormPrinter", "props": { "value": ":dsl" } }}...}
打开 templates 表格,点击编辑一个模板,即可使用可视化编辑器制作表单。
对于活动报名、预约注册等 C 端页面,需要个性化设计来提升用户体验。对于此类场景,可以有针对性的设计一组模板,使用任意前端技术栈实现。这里提供一个 VUE3 实现的 DEMO。 源码地址: https://github.com/YaoApp/demo-widget-front
添加一个 GET /page/form/setting/:name
API , 在 apis 文件夹下,添加一个 page.http.json 文件, 添加一个接口,第一个参数为 表格名称.
{"name": "Table Setting","version": "1.0.0","description": "Table Setting","group": "page","guard": "-","paths": [{"path": "/form/setting/:name","method": "GET","guard": "-","process": "xiang.table.Setting","in": ["$param.name", ":query"],"out": { "status": 200, "type": "application/json" }}]}
源码地址: https://github.com/YaoApp/demo-widget/blob/main/apis/page.http.json
const url = `${window.location.protocol}//${window.location.host}/api/page/form/setting/${formName}`;const response = fetch(url);response.then((res) => {return res.json();}).then((data) => {formTitle.value = data.name;const fieldset = data?.edit?.layout?.fieldset || [];const columns = fieldset.length > 0 ? fieldset[0]?.columns : [];const mapping = data?.columns || {};columns.forEach((col: any) => {let column = mapping[col.name] || false;if (column?.edit) {let name = column.edit.props?.value || "";column.edit.label = col.name;column.edit.field = name.replace(":", "");column.edit.type = components[column.edit.type];formItems.value.push(column.edit);}});loading.value = true;}).catch((err) => {console.log("ERR", err);failure.value = err.message;});
源码地址: https://github.com/YaoApp/demo-widget-front/blob/main/vue3/src/App.vue
使用 component
组件,根据配置渲染表单
<template><div v-if="loading"><div class="header">{{ formTitle }}</div><form><div class="form-item" v-for="item of formItems" :key="item.label"><div class="label">{{ item.label }}</div><component :is="item.type" :name="item.field"></component></div><div class="form-item" v-if="formItems"><button class="button" type="button">Submit</button></div></form></div><div v-else-if="failure" class="failure">{{ failure }}</div><div v-else><div>Loading...</div></div></template>
源码地址: https://github.com/YaoApp/demo-widget-front/blob/main/vue3/src/App.vue
YAO 内建了一个 HTTP server,将制品复制到 ui 目录即可访问
npm run buildcp -r dist ../demo-widget/ui/vue3
源码地址: https://github.com/YaoApp/demo-widget/tree/main/ui/vue3
打开浏览器,输入 http://your-host:port/xiang/login/admin
进入后台,录入并保存一个表单。
默认用户名: xiang@iqka.com
默认密码: A123456p+
打开 http://your-host:port/vue3/?form=dyform.instance_1
即可访问自定义表单页面