---
description: 百度 Amis(基于 JSON 来配置页面)
---

# butterfly-admin(json2web)

## 1 部署

{% embed url="https://github.com/meetbill/butterfly-admin" %}

### 1.1 在 butterfly 项目中部署

<pre><code>// (1) 拷贝静态文件
cp -rf butterfly-admin/static &#x3C;butterfly>/
cp -rf butterfly-admin/templates/* &#x3C;butterfly>/templates/

// (2) 编写首页 handler(&#x3C;butterfly>/handlers/__init__.py)
<strong>----------------------------------------------------------code
</strong>#!/usr/bin/python
# coding=utf8
"""
# Description:
    index handler
"""
from xlib.httpgateway import Request
from xlib import retstat


def main(req):
    """
    首页 handler
    """
    isinstance(req, Request)
    with open("./templates/index.html") as f:
        context = f.read()
    return retstat.HTTP_OK, context, [("Content-Type", "text/html")]
</code></pre>

### 1.2 在 nginx 中部署

#### 1.2.1 部署结构

```
butterfly-xxx
butterfly-ruqi
butterfly-auth
butterfly-admin
├── conf                                    // nginx 配置文件
│   ├── mime.types
│   └── nginx.conf
├── logs                                    // nginx 日志
├── run.sh
├── sbin
│   └── nginx
├── static                                  // butterfly-admin static
│   ├── logo
│   └── pages
└── templates                               // butterfly-admin templates
    ├── favicon.ico
    ├── index_sso.html                      // 用于单点登录场景
    └── index.html
```

#### 1.2.2 nginx 配置文件说明

在nginx的location和配置中location的顺序没有太大关系。与location表达式的类型有关。相同类型的表达式，字符串长的会优先匹配。

```

第一优先级：等号类型（=）的优先级最高。一旦匹配成功，则不再查找其他匹配项。
第二优先级：^~类型表达式。一旦匹配成功，则不再查找其他匹配项。
第三优先级：正则表达式类型（~ ~*）的优先级次之。如果有多个location的正则能匹配的话，则使用正则表达式最长的那个。
第四优先级：常规字符串匹配类型。按前缀匹配。
```

> 例子

<pre><code><strong>--------------------------匹配到之后，nginx 停止搜索其他匹配
</strong><strong>location = /auth/verification {}    --> butterfly_auth
</strong>location = /auth/ssologin {}        --> butterfly_auth
location = / {}
location = /index_sso.html {}
location = /favicon.ico {}
location = /butterfly_401 {}
--------------------------匹配到之后，nginx 停止搜索其他匹配，一般用来匹配目录
location ^~ /xingqiao/ {}           // 根据前缀将请求转到相应 app
location ^~ /wuxing/ {}             // 根据前缀将请求转到相应 app
--------------------------URI 正则表达式，不区分大小写
location ~* /static/ {}             // 静态文件
--------------------------前缀匹配
location / {}
</code></pre>

## 2 第一个程序

### 2.1 /demo\_api/ping

#### 2.1.1 后端返回

> \<butterfly> /demo\_api/ping

```
{
    "stat": "OK",
    "randstr": "CbYkjKSMx1g96KMr2obpT55xbf9OSV2HlIRvd4ZjIaSlnKfCOPMinbgQZAwWM(QToS2iypeWaHrC74iJKKQjsF6O6FuRO)TvmzTiesVcshsrXfOhQCAFCKqzJLNV3MDoEuKNWn8",
}
```

#### 2.1.2 前端 json

> &#x20;\<butterfly>/static/pages/demo\_ping/ping.json

```
{
  "type": "page",
  "title": "Dashboard",
  "initApi": "/demo_api/ping",
  "body": "ping is ${randstr}"
}
```

#### 2.1.3 测试

```
页面访问：http://<ip>:<port>/main#/demo_ping/ping

页面路由 /demo_ping/ping 配置在 <butterfly>/static/pages/site.json
```

## 3 接口例子

### 3.1 table

#### 3.1.1 Params

* orderBy : (str) 排序字段(适配 amis)
* orderDir : (str) asc/desc(适配 amis)
* page\_index : (int) 页数
* page\_size : (int) 每页显示条数

#### 3.1.2 Result

```
{
    "stat": "OK",
    "data": {
        "total": 7,
        "list": [
            {
                "name": "1G",
                "spec": 1
                "<name>": <value>
            }
        ]
    }
}
```

#### 3.1.3 amis 配置

```
{
      "type": "crud",
      "name": "sample",
      "api": {
        "method": "get",
        "url": "http://127.0.0.1:8585/...",
        "adaptor": "if (payload.stat == 'OK') {return {status: 0, msg:'OK', data:{items: payload.data.list,count: payload.data.total}};} else {return {status: 1, msg:payload.stat, data:{items: [],count: 0}};};"
      },
      "pageField": "page_index",
      "perPageField": "page_size",
      ...
}
```

### 3.2 chart

#### 3.2.1 bar 柱状图

```
{
    "stat": "OK",
    "data": {
        "yAxis": {},
        "series": [
            {
                "data": [
                    4.921490212586824,
                    5.949157733537519,
                    1.9482631189948263
                ],
                "type": "bar",
                "name": "mem/cpu ratio"
            }
        ],
        "title": {
            "text": "mem/cpu ratio"
        },
        "tooltip": {},
        "xAxis": {
            "data": [
                "total",
                "allocated",
                "available"
            ]
        },
        "legend": {}
    }
}
```

#### 3.2.2 pie 饼图

```
{
    "stat": "OK",
    "data": {
        "series": [                                  // 图表数据
            {
                "data": [
                    {
                        "name": "free_available",
                        "value": 1353
                    },
                    ...
                ],
                "type": "pie",                       // 图表类型
                "name": "cpu",
                "label": {
                    "borderColor": "#8C8D8E",
                    "borderRadius": 4,
                    "formatter": "{a}\n{b} ({d}%)",
                    "borderWidth": 1,
                    "backgroundColor": "#F6F8FC"
                }
            }
        ],
        "legend": {},                                // 图例：图例中的 data 数据来源于 series 中每个对象的 name,
                                                              图例可以帮助我们对图表进行筛选
                                                     // eg:  {"data": ["free_available", ...]},
        "tooltip": {                                 // 提示框：当鼠标移入到图表或者点击图表时，展示出的提示框
            "trigger": "item",                       // 触发类型：item/axis/none
                                                     //   'item'：数据项图形触发，主要在散点图，饼图等无类目轴的图表
                                                     //   'axis'：坐标轴触发，主要在柱状图，折线图等会使用类目轴的图表
                                                     //   'none'：怎么样都不触发。
            "formatter": "{a} {b}:{c} ({d}%)"        // 格式化显示：字符串模板
        },
        "title": {                                   // 标题
            "text": "cpu ratio"
        }
    }
}
```

## 4 chart 库

> lib\_echarts.py

```
#!/usr/bin/python
# coding=utf8
"""
# Author: wangbin34
# Created Time : 2023-02-20 11:36:44

# File Name: lib_echarts.py
# Description:

"""


def convert_to_bar_data(name, source_data, item_name_key, item_value_key):
    """
    Args:
        name: (string) chart name
        source_data: (list)
        item_name_key: (string) name key
        item_value_key: (string) value key

    Returns:
    Example:
        {
            "yAxis": {},
            "series": [
                {
                    "data": [
                        4.921490212586824,
                        5.949157733537519,
                        1.9482631189948263
                    ],
                    "type": "bar",
                    "name": "mem/cpu ratio"
                }
            ],
            "title": {
                "text": "mem/cpu ratio"
            },
            "tooltip": {},
            "xAxis": {
                "data": [
                    "total",
                    "allocated",
                    "available"
                ]
            },
            "legend": {}
        }
    """
    assert isinstance(source_data, list)
    name_list = []
    value_list = []
    for item_data in source_data:
        name_list.append(item_data[item_name_key])
        value_list.append(item_data[item_value_key])

    # AMIS/echarts
    data = {}
    data["tooltip"] = {}
    data["legend"] = {}
    data["title"] = {"text": name}

    data["xAxis"] = {}
    # data name
    data["xAxis"]["data"] = name_list
    data["yAxis"] = {}

    chart_data = {}
    # chart name
    chart_data["name"] = name
    chart_data["type"] = "bar"
    # data value
    chart_data["data"] = value_list
    data["series"] = [chart_data]
    return data


def convert_to_pie_data(name, source_data, item_name_key, item_value_key):
    """
    Args:
        name: (string) chart name
        source_data: (list)
        item_name_key: (string) name key
        item_value_key: (string) value key

    Returns:
    Example:
    {
        "series": [                                  // 图表数据
            {
                "data": [
                    {
                        "name": "free_available",
                        "value": 1353
                    },
                    ...
                ],
                "type": "pie",                       // 图表类型
                "name": "cpu",
                "label": {
                    "borderColor": "#8C8D8E",
                    "borderRadius": 4,
                    "formatter": "{a}\n{b} ({d}%)",
                    "borderWidth": 1,
                    "backgroundColor": "#F6F8FC"
                }
            }
        ],
        "legend": {},                                // 图例：图例中的 data 数据来源于 series 中每个对象的 name,
                                                              图例可以帮助我们对图表进行筛选
                                                     // eg:  {"data": ["free_available", ...]},
        "tooltip": {                                 // 提示框：当鼠标移入到图表或者点击图表时，展示出的提示框
            "trigger": "item",                       // 触发类型：item/axis/none
                                                     //   'item'：数据项图形触发，主要在散点图，饼图等无类目轴的图表
                                                     //   'axis'：坐标轴触发，主要在柱状图，折线图等会使用类目轴的图表
                                                     //   'none'：怎么样都不触发。
            "formatter": "{a} {b}:{c} ({d}%)"        // 格式化显示：字符串模板
        },
        "title": {                                   // 标题
            "text": "cpu ratio"
        }
    }
    """
    assert isinstance(source_data, list)
    item_list = []
    for item_data in source_data:
        item_list.append({"name": item_data[item_name_key], "value": item_data[item_value_key]})

    # AMIS/echarts
    data = {}
    data["tooltip"] = {
        "trigger": "item",
        "formatter": "{a} {b}:{c} ({d}%)"
    }
    data["legend"] = {}
    data["title"] = {"text": name}

    chart_data = {}
    # pie name
    chart_data["name"] = name
    chart_data["type"] = "pie"
    # label
    chart_data["label"] = {
        "formatter": '{a}\n{b} ({d}%)',
        "backgroundColor": '#F6F8FC',
        "borderColor": '#8C8D8E',
        "borderWidth": 1,
        "borderRadius": 4,
    }
    chart_data["data"] = item_list
    data["series"] = [chart_data]
    return data
```

## 5 附录

amis 官方文档：[https://baidu.github.io/amis/zh-CN/docs/index](https://baidu.github.io/amis/zh-CN/docs/index)

配置项参考文档：https://echarts.apache.org/zh/option.html#title

echarts python 库：[https://github.com/yufeiminds/echarts-python](https://github.com/yufeiminds/echarts-python)
