UiAuto|开发规范

  最近公司在做数字员工的开发,在前面的博文中大概能看出我对PYTHON脚本、KETTLE、RPA(UIPATH、Power Automat)都做过一些自动办公的尝试。最终我们公司选择了UIAUTO来作为基础平台,究其原因,是它对PYTHON的二开有很大的兼容度,极其灵活!造轮子的过程何尝不是一种快乐呢?
  百度百科搜索RPA给出的解释是“机器人流程自动化(Robotic process automation,简称RPA)是以软件机器人及人工智能(AI)为基础的业务过程自动化技术”。但我始终认为RPA是在线办公向智能办公过渡的产物,早期的RPA依赖的是屏幕和键鼠的配合,顶多加上开源的OCR识别,很多软件/厂商就对外宣称是智能机器人了。PYTHON的火速发展才是RPA技术成熟的原因,PYTHON各种奇妙的库才让RPA有了更多发展的机会。UIAUTO与其说是RPA工具,更不如说是一个基础平台,有基础的图形界面、相对易用的管理界面、还有灵活的二开方案。它提供标准的开发规范,开发人员可以将写好的JS、PYTHON功能封装为插件,实现相关常见的调用。这种将设计权交给终端开发人员的方案在实践上是很巧妙的,终端开发可以任性魔改,实现各类场景需求。
  开发规范记录如下,便于后续翻阅:

插件目录结构插件目录结构

1
2
3
4
5
6
7
8
9
10
demo
└─ 1.0.0 //插件版本,与package.json描述需一致
├─ index.js //js逻辑入口文件,命名必须为index
├─ index.py //python逻辑入口文件,命名必须为index
├─ node_modules //nodejs依赖库
├─ requirements.txt //python依赖库
├─ package-lock.json
├─ package.json
├─ packages
└─ util.js //自定义逻辑文件

插件开发插件开发

插件由描述文件及入口程序组成,入口程序主要是暴露插件每个操作的执行方法(基于Java语言开发的插件的入口程序是编译打包的jar包文件)。

插件依赖插件依赖

对于基于Python语言开发的插件,通过添加requirements.txt文件来配置依赖库。
对于基于NodeJS语言开发的插件是在package.json文件内的dependencies属性配置依赖库。
对于基于Java语言开发的插件是在编译jar包时就需要把依赖库一起打包。

描述文件结构描述文件结构

描述文件内容为标准JSON格式,以下注释为方便理解变量意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{
"id": "hello-world",
"name": "hello-world", // project name,
"description": "say hello from UiAuto!",
"version": "1.0.0",
"author": "UiAuto",
"language": "nodejs",
"license": "MIT",
"dependencies": {
"lodash": "4.17.11" // depandencies of the plugin
},
"uiauto_config": {
"attribution_id": "software_automation", //first level category
"attribution_name": "软件自动化", //first level category name
"operations": [{
"category_id": "plugin-template", // class of the operation, sort the opterations according to this param
"category_name": "模板插件", // name of the class, if we don't have the category_id above yet, this name will be shown on front - end "operation_id": "plugin-one",
"operation_name": "插件一",
"method": "sayHello", // if this opteration is executed, function named "sayHello" in "./index.js" ("./index.py" in python) will be activated "type": "Convention", // we have these types yet => [Start, Condition, Convention, Circulation, Script, End]. Only Condition and Convention can be defined
"input": [{
"name": "必填属性", // label of this input group
"id": "required_params",
"properties": [{
"id": "addressee", // id of this input
"name": "用户名", // label of this input
"type": "text", // type of this input, you can read the detail of various types below
"required": true, // is the value required
"value": "uiauto_group" // the default value
},
{
"id": "file",
"name": "文件",
"type": "file",
"required": true,
"value": ""
}
]
}, {
"name": "可选属性",
"id": "unrequired_params",
"properties": [{
"id": "drink",
"name": "饮品",
"required": false,
"type": "select",
"value": "tea" // default value 「默认值」
"options": {
"multiple": true, // required option, could the user make multiple choices or not
"choices": [{
"value": "juice",
"label": "果汁"
}, {
"value": "coffee",
"label": "咖啡"
}, {
"value": "tea",
"label": "茶"
}] // enumerate groups of value and label
}
}]
}],
"output": {
"is_allow_global_use": true,
"description": "返回执行结果,true 或者 false",
"value": ""
}
}]
}
}

属性类型总览属性类型总览

text 普通文本类型普通文本类型

1
2
3
4
{
"type": "text",
"value": "default value"// 默认值
}
1
result: <String>

password 密码文本类型密码文本类型

*密码文本类型的前端展示形式是 “···”

1
2
3
4
{
"type": "password",
"value": "default value"// 默认值
}
1
result: <String>

string 文本展示类型文本展示类型

该类型下的文本只做展示用途,不允许编辑

1
2
3
4
{
"type": "string",
"value": "value which can not be edited"
}
1
result: null

file 文件类型文件类型

该类型目前仅支持选择一个文件

1
2
3
{
"type": "file"
}
1
result: <String <filePath>>

color 颜色类型颜色类型

1
2
3
{
"type": "color"
}
1
result: <String>

checkbox 多选类型多选类型

1
2
3
4
5
6
    "type": "checkbox",
"value": [],// default value 「默认值」
"options": {
"checked": [] // 默认选中
}
}
1
result: <Array>

dateTimeRange 时间段类型时间段类型

options.type 不同, value 需求不同,但值可被兼容,若插件需要精确到时间,但默认值没有精确到时间(不推荐),则会默认设定为世界协调时间
(UTC)/ 格林尼治时间 (GMT) 00:00:00 ,即若在东八时区,则默认值为 08:00:00

1
2
3
4
5
6
7
{
"type": "dateTimeRange",
"value": ["2019-05-01 00:00:00", "2019-10-01 12:00:00"]// default value 「默认值」
"options": {
"type": "daterange" // "datetimerange" | "daterange" | "monthrange"
}
}
1
result: <Array(2)>

inputNumber 计数器类型计数器类型

1
2
3
4
{
"type": "inputNumber",
"value": 10 // 默认值
}
1
result: <Number>

conditions 条件类型条件类型

该类型的值均为不等式字符串

1
2
3
4
{
"type": "conditions",
"value": ["value1 > 10", "value2 < 50"] // 默认值
}
1
result: <Array>

select 下拉列表类型下拉列表类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"type": "select",
"value": "tea" // default value 「默认值」
"options": {
"multiple": true, // required option, could the user make multiple choices or not
"choices": [{
"value": "juice",
"label": "果汁"
}, {
"value": "coffee",
"label": "咖啡"
}, {
"value": "tea",
"label": "茶"
}] // enumerate groups of value and label
}
}
1
2
!options.multiple: result: <String>
options.multiple: result: <Array>

slider 滑块类型滑块类型

1
2
3
4
5
6
7
8
9
{
"type": "slider",
"value": 10 // default value 「默认值」
"options": {
"step": 10, // unrequired option, default 0
"max": 100, // maximum, default 100
"min": 0 // minimum, defalut 0
"precision": 1 // precision, defalut 1
}
1
result: <String>

switch 开关类型开关类型

1
2
3
4
{
"type": "switch",
"value": false// default value 「默认值」
}
1
result: <Boolean>

json JSON 类型类型

1
2
3
4
5
6
{
"type": "json",
"value": {
"demo_key": "demo_value"
} // default value 「默认值」
}
1
result: <Boolean>

code 编辑器类型编辑器类型

1
2
3
4
{
"type": "code",
"value": "print('Hello World!')"// default value 「默认值」
}
1
result: <Boolean>

screenshot 截屏类型截屏类型

1
2
3
4
{
"type": "screenshot",
"value: "" // image path
}
1
result: <String>

uiselector ui 选择类型选择类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
"type": "uiselector",
"value": {
"system": {
"DesktopSize": "1920, 960",
"Radio": 1,
"PointInScreen": "601, 287",
"PointRelative_X": 0.31,
"PointRelative_Y": 0.
},
"wnd": {
"control_type": 0,
"control_type_name": null,
"name": null,
"class_name": null,
"text": null,
"value": null,
"rect": "0,0,0,0",
"relative_x": 0,
"relative_y": 0,
"main_window_property": null
},
"html": {
"element": null,
"browser": "Chrome",
"id": "",
"tag": "a",
"text": "基金排行",
"value": null,
"xpath": "//*[@id='body']/div/div[4]/div/div/div[1]/div[2]/ul/li[1]/a[3]",
"full_xpath": "/html/body/div[2]/div/div[4]/div/div/div[1]/div[2]/ul/li[1]/a[3]",
"frame": null,
"left": 581,
"top": 286,
"width": 48,
"height": 14
},
"element_screenshot": "data:image/png;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQg
KDBQNDAsLDBkSEw8UHRofHh0 "
}
}
1
result: <Object>

属性类型通用配置项属性类型通用配置项

属性输入框联动属性输入框联动

如果你在使用UiAuto进行开发的时候,需要根据使用者的输入动态渲染/隐藏某些属性输入框或想实现其他复杂的具有联动需求的输入配置,则可以通过参数 “show_if” 进行配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
{

...

"uiauto_config": {
"operations": [{

...

"input": [{
"name": "必填属性",
"id": "required_params",
"properties": [{
"id": "dishType",
"name": "菜品类型",
"required": true,
"type": "select",
"value": "single" // default value 「默认值」
"options": {
"multiple": false, // required option, could the user make multiple choices or not
"choices": [{
"value": "single",
"label": "单点"
}, {
"value": "package",
"label": "套餐"
}] // enumerate groups of value and label
}
}, {
"id": "stapleFood",
"name": "主食",
"required": true,
"type": "select",
"value": "friedRice" // default value 「默认值」
"options": {
"multiple": false, // required option, could the user make multiple choices or not
"choices": [{
"value": "pasta",
"label": "意大利面"
}, {
"value": "friedRice",
"label": "炒饭"
}, {
"value": "steak",
"label": "牛排"
}] // enumerate groups of value and label
}
}]
}, {
"name": "可选属性",
"id": "unrequired_params",
"properties": [{
"id": "drink",
"name": "饮品",
"show_if": "$input.required.dishType==='package'",
"required": false,
"type": "select",
"value": "tea" // default value 「默认值」
"options": {
"multiple": false, // required option, could the user make multiple choices or not
"choices": [{
"value": "juice",
"label": "果汁"


}, {


"value": "coffee",
"label": "咖啡"
}, {
"value": "tea",
"label": "茶"
}] // enumerate groups of value and label
}
}]
}],
"output": {
"is_allow_global_use": true,
"description": "返回执行结果,true 或者 false",
"value": ""
}
}]
}
}

以上代码在可选属性里对“饮品”属性框配置了 “show_if”: “$input.required.dishType===‘package’” 则控制为:当本插件输入框id为 “required”,id为 “dishType” 的输入框值为 “package” 时,显示该属性配置。
目前 “show_if” 可配置javascript规范下的表达式,其中$input是指在本插件输入属性中查找。


商业转载请联系作者获得授权,非商业转载请注明出处。

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

UiAuto|开发规范
http://hncd1024.github.io/2023/05/27/UiAutoDevelopedStandard/
作者
CHEN DI
发布于
2023-05-27
许可协议