Yao 折腾手记:如何快速创建一套管理系统

文章首发于个人公号:阿拉平平

有开发经验的小伙伴肯定知道,要独立开发一套管理系统并非易事。从设计数据库,到开发接口,再到编写前端页面,想想就让人头大。如果需求不是很复杂,我们可以借助低代码应用引擎来快速开发。

项目介绍

Yao[1] 是一款 Go 语言驱动的低代码应用引擎,通过编写 JSON 文件即可快速制作 API 接口,数据管理系统 ,命令行工具等应用程序,应用可以运行在本地、云端和物联网设备上。

快速安装

Yao 可以通过脚本或容器来安装,官方推荐后者,所以这里我们使用 Docker 来部署。

运行以下命令创建容器:

# 注意修改挂载的目录
docker run -d --name yao -v <project root>:/data/app -p 5099:5099 yaoapp/yao:0.9.2-amd64-dev

容器启动后,进入容器:

docker exec -it yao bash

在项目目录中,运行初始化命令:

yao init

接着创建数据表:

yao migrate

初始化菜单:

yao run flows.setmenu

完成以上步骤后,启动服务:

yao start

服务启动后,用浏览器访问 https://<server-ip>:5099/xiang/login/admin,输入用户名:xiang@iqka.com, 密码: A123456p+ 登录。

使用说明

接下来,我将介绍 Yao 的用法,其中包含:

  1. 基本用法:借助测试数据,了解 Yao 界面上的功能。
  2. 新建内容:新建新的内容,包括数据、接口和界面。

基本用法

Yao 在初始化后会有些测试数据,在界面中可以看到表单信息:

我们可以查看、编辑数据:

Yao 还有张用户表,支持增删改查:

在菜单界面可以配置左侧显示的内容:

新建内容

Yao 界面上的功能大致如此,接下来我们建下自己的内容。这里我打算实现一个简单的图书管理功能。

先从数据开始。我们回到项目目录,在 models 下新建一个 book.mod.json 文件,内容如下:

{
    "name": "Book",
    "table": {
        "name": "book",
        "comment": "Book"
    },
    "columns": [{
            "label": "ID",
            "name": "id",
            "type": "ID",
            "comment": "ID"
        },
        {
            "label": "SN",
            "name": "sn",
            "type": "string",
            "unique": true
        },
        {
            "label": "Name",
            "name": "name",
            "type": "string",
            "index": true
        },
        {
            "label": "Kind",
            "name": "kind",
            "type": "enum",
            "option": ["科幻", "名著"],
            "default": "科幻",
            "index": true
        },
        {
            "label": "Description",
            "name": "desc",
            "type": "string",
            "comment": "Description"
        },
        {
            "label": "Score",
            "name": "score",
            "type": "integer",
            "comment": "Score"
        }
    ],
    "values": [{
            "sn": "100001",
            "name": "水浒传",
            "kind": "名著",
            "desc": "三个女人和一百零五个男人的故事",
            "score": 9
        },
        {
            "sn": "100002",
            "name": "三体",
            "kind": "科幻",
            "desc": "不要回答!不要回答!不要回答!",
            "score": 9
        }
    ],
    "option": {
        "timestamps": true,
        "soft_deletes": true
    }
}

然后在项目目录中运行以下命令:

yao migrate -n book

需要注意的是,该命令的结果不会在前台显示,而是写到 logs/application.log 中。

针对这种情况,我们可以先查询下数据,如果数据能够正常显示,则说明数据表已创建:

yao run models.book.get '::{}'

Run: models.book.get
args[0]: {}
--------------------------------------
models.book.get Response
--------------------------------------
[
    {
        "created_at": "2022-07-27 05:41:32",
        "deleted_at": null,
        "desc": "三个女人和一百零五个男人的故事",
        "id": 1,
        "kind": "名著",
        "name": "水浒传",
        "score": 9,
        "sn": "100001",
        "updated_at": null
    },
    {
        "created_at": "2022-07-27 05:41:32",
        "deleted_at": null,
        "desc": "不要回答!不要回答!不要回答!",
        "id": 2,
        "kind": "科幻",
        "name": "三体",
        "score": 9,
        "sn": "100002",
        "updated_at": null
    }
]
--------------------------------------
✨DONE✨

再编写接口。在 apis 下新建一个 book.http.json 文件,内容如下:

{
    "name": "书籍",
    "version": "1.0.0",
    "description": "书籍接口",
    "group": "book",
    "guard": "bearer-jwt",
    "paths": [{
            "path": "/search",
            "method": "GET",
            "guard": "-",
            "process": "models.book.Paginate",
            "in": [":query-param", "$query.page", "$query.pagesize"],
            "out": {
                "status": 200,
                "type": "application/json"
            }
        },
        {
            "path": "/save",
            "method": "POST",
            "guard": "-",
            "process": "models.book.Save",
            "in": [":payload"],
            "out": {
                "status": 200,
                "type": "application/json"
            }
        }
    ]
}

在这个文件中,我定义了两个接口:/search/save,用于查询和创建。我们先用接口创建新的数据:

curl -X POST http://127.0.0.1:5099/api/book/save \
   -H 'Content-Type: application/json' \
   -d '{ "sn": "100003", "name": "三国演义", "kind": "名著", "desc": "东汉末年分三国", "score": 9 }'

查询刚刚创建的数据,如果结果返回正常,说明接口功能无误。

curl 'http://127.0.0.1:5099/api/book/search?where.name.match=三国演义&page=1&pagesize=1'

最后编写界面。在 tables 目录下新建一个 book.tab.json 文件,内容如下:

{
    "name": "Book",
    "version": "1.0.0",
    "decription": "Book",
    "bind": {
        "model": "book"
    },
    "apis": {},
    "columns": {
        "ID": {
            "label": "ID",
            "view": {
                "type": "label",
                "props": {
                    "value": ":id"
                }
            }
        },
        "SN": {
            "label": "SN",
            "view": {
                "type": "label",
                "props": {
                    "value": ":sn"
                }
            },
            "edit": {
                "type": "input",
                "props": {
                    "value": ":sn"
                }
            }
        },
        "Name": {
            "label": "Name",
            "view": {
                "type": "label",
                "props": {
                    "value": ":name"
                }
            },
            "edit": {
                "type": "input",
                "props": {
                    "value": ":name"
                }
            }
        },
        "Kind": {
            "label": "Kind",
            "view": {
                "type": "label",
                "props": {
                    "value": ":kind"
                }
            },
            "edit": {
                "type": "select",
                "props": {
                    "value": ":kind",
                    "options": [{
                            "label": "科幻",
                            "value": "科幻"
                        },
                        {
                            "label": "名著",
                            "value": "名著"
                        }
                    ]
                }
            }
        },
        "Score": {
            "label": "Score",
            "view": {
                "type": "label",
                "props": {
                    "value": ":score"
                }
            },
            "edit": {
                "type": "input",
                "props": {
                    "value": ":score"
                }
            }
        },
        "Description": {
            "label": "Description",
            "view": {
                "type": "label",
                "props": {
                    "value": ":desc"
                }
            },
            "edit": {
                "type": "textArea",
                "props": {
                    "value": ":desc",
                    "rows": 4
                }
            }
        }
    },
    "filters": {
        "Keywords": {
            "@": "f.Keywords",
            "in": ["where.name.match"]
        }
    },
    "list": {
        "primary": "id",
        "layout": {
            "columns": [{
                    "name": "SN",
                    "width": 100
                },
                {
                    "name": "Name",
                    "width": 200
                },
                {
                    "name": "Score",
                    "width": 300
                },
                {
                    "name": "Kind"
                }
            ],
            "filters": [{
                "name": "Keywords"
            }]
        },
        "actions": {
            "create": {
                "type": "button",
                "props": {
                    "label": "添加书籍",
                    "icon": "fas fa-plus"
                }
            },
            "pagination": {
                "props": {
                    "showTotal": true
                }
            }
        },
        "option": {
            "operation": {
                "unfold": true
            }
        }
    },
    "edit": {
        "primary": "id",
        "layout": {
            "fieldset": [{
                "columns": [{
                        "name": "SN",
                        "width": 6
                    },
                    {
                        "name": "Name",
                        "width": 6
                    },
                    {
                        "name": "Kind",
                        "width": 6
                    },
                    {
                        "name": "Score",
                        "width": 6
                    },
                    {
                        "name": "Description",
                        "width": 24
                    }
                ]
            }]
        },
        "actions": {
            "cancel": {},
            "save": {
                "type": "button",
                "props": {
                    "label": "Save"
                }
            },
            "delete": {
                "type": "button",
                "props": {
                    "label": "Delete"
                }
            }
        }
    }
}

回到菜单界面,把建好的书籍界面添加进去:

重新登录系统,可以看到书籍界面:

写在最后

可以看到,我们用 Yao 添加新内容时,基本都是在和 JSON 打交道,没有涉及到代码。所以对于需求不复杂的系统,使用低代码引擎来开发或许是个不错的选择。

References

[1] Yao: https://github.com/YaoApp/yao

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容