# 页面结构定义

一个完整的页面定义,它包含了页面的头部、内容、底部、事件、母版、插槽、变量、数据源、函数、样式、交互动作编排等。

# 页面结构描述

页面定义的JSON主要包含以下字段:

  • type: {string} 固定值"AdaptivePage"
  • version: {string} 协议版本,从2.0版本开始
  • header: {array} 页头内容,在里面放置组件的数组
  • body: {array} 页面内容,在里面放置组件的数组
  • footer: {array} 页脚内容,在里面放置组件的数组
  • events: {object} 页面事件
  • master: {string} 母版生成页面专用:如果页面由母版生成,master表示母版ID
  • slots: {object} 母版生成页面专用:母版区域对应的插槽
  • variables: {object} 定义页面可使用的变量
  • dataSources: {array} 定义页面数据源
  • functions: {object} 定义页面函数
  • style: {string} html属性:style
  • class: {string} html属性:class
  • orchestrations: {object} 用于保存页面交互动作的编排数据,例如点击按钮后执行一系列动作
  • debugger: {boolean} 设置为true给模板编译后的render函数添加一个debugger,方便调试
  • meta: {object} 页面额外的元数据信息,例如在设计器里面会补充一些设计器专属的页面信息

以下是个页面结构示例:

{
  "type": "AdaptivePage",
  "version": "2.0", 
  "header": [],
  "body": [],
  "footer": [],
  "events": {},
  "master": "",
  "slots": {},
  "variables": {},
  "dataSources": [],
  "functions": {},
  "style": "",
  "class": "", 
  "orchestrations": {},
  "debugger": true,
  "meta": {
    "title": "页面标题",
    "platform": "pc"
  }
}

# 页面内容(body)

页面内容区域,由多个组件组成,通过 children 支持多层级嵌套。 注意 header, footer 里面的内容和 body 一样,都是一个组件数组。

{
  "body": [
    {
      "type": "", //组件类型ID
      "id": "", //组件唯一ID
      "props": {
        "p1": "abc", //属性值为普通值
        "p2": "${var1}" //属性值为表达式
      },
      //组件事件
      "events": {},
      //组件slot区域
      // 当组件只有一个默认(default)插槽时,可用children属性代替slots
      // children和slots是二选一
      "slots": {},
      "children": [], // 多层级嵌套
      "style": "", // html属性:style
      "class": "" // html属性:class
    }
  ]
}

# 页面母版(master)

当我们在设计页面时,发现有多个页面外框都是一样的,只有某些部分内容不同,这时候可以基于母版页来设计页面

{
  "master": "OR56nO-xh", //母版ID,此ID对应的内容也是一个完整的页面运行时定义
  "slots": {
    //slot区域ID,真实的页面是基于母版页内容,用这里的区域内容对应填充到母版页的对应slot区域
    "slot1": [
      {
        "text": "我是自定义的内容",
        "type": "TextBlock"
      }
    ]
  }
}

# 页面变量(variables)

页面全局变量定义,是一个schema,可以被组件的属性绑定或者由操作去修改,从而实现复杂的组件交互

{
  "variables": {
    "appId": {
      "title": "应用ID",
      "type": "string",
      /** 变量值来源:目前仅支持request */
      "source": "request",
      /** source为request的变量值不可修改自动为request.params.appId */
      "default": "${request.params.appId}",
      "orderNo": 3
    },
    //属性ID
    "keyword": {
      "title": "搜索关键字", //属性中文名
      "type": "string", //属性类型
      "orderNo": 0 //属性排序号,控制属性的显示顺序
    },
    "pagination": {
      "title": "分页",
      "type": "object",
      "orderNo": 1,
      //对象类型属性子属性定义
      "properties": {
        "rowsPerPage": {
          "title": "每页总数",
          "type": "number",
          "orderNo": 0,
          "default": 10 //默认值为普通值
        },
        "rowsNumber": {
          "title": "总数",
          "type": "number",
          "orderNo": 1,
          "default": "${paginationVar.rowsNumber}" //默认值绑定表达式
        },
        "page": {
          "title": "页码",
          "type": "number",
          "orderNo": 2,
          "default": 0
        }
      }
    }
  }
}

# 页面数据源(dataSources)

页面数据源主要是用来查询数据,数据源是一个数组,每个数据源是一个对象,对象中包含了数据源的配置信息,例如:url、method、params、data、headers 等。以下是一个简单的页面数据源结构示例:

{
 "dataSources": [
    {
      "id": "query_SampleLeave",
      "title": "查询列表",
      "multiple": true,
      "schema": {
        "id": {
          "type": "string",
          "title": "唯一ID"
        },
        "title": {
          "type": "string",
          "title": "标题"
        },
        "reason": {
          "type": "string",
          "title": "请假事由"
        },
        "endDate": {
          "type": "string",
          "title": "结束日期"
        },
        "startDate": {
          "type": "string",
          "title": "开始日期"
        },
        "isDeleted": {
          "type": "boolean",
          "title": "是否删除"
        },
        "createdBy": {
          "type": "string",
          "title": "创建人"
        },
        "tenantId": {
          "type": "string",
          "title": "租户ID"
        },
        "createdByName": {
          "type": "string",
          "title": "创建人姓名"
        },
        "createdAt": {
          "type": "string",
          "title": "创建时间"
        },
        "updatedBy": {
          "type": "string",
          "title": "更新人"
        },
        "updatedByName": {
          "type": "string",
          "title": "创建人姓名"
        },
        "updatedAt": {
          "type": "string",
          "title": "更新时间"
        }
      },
      "lazy": false,
      "autoReload": true,
      "url": {
        "type": "ServicePath",
        "source": "local",
        "value": "/sample_leave",
        "processor": "ServicePathProcessor"
      },
      "method": "GET",
      "params": {
        "page": null,
        "size": null,
        "limit": null,
        "offset": null,
        "select": null,
        "filters": null,
        "search": null,
        "expand": null,
        "joins": null,
        "orderby": null,
        "total": "${true}"
      }
    }
  ]
}

每一个数据源对象定义如下:

{
  /** 数据源id */
  id: string;
  /** 数据源类型 */
  type?: string;
  /** 数据源名称 */
  title?: string;
  /** 数据源是否为多值:例如列表查询一般为多值,表单数据为单值 */
  multiple?: boolean;
  /** 数据项的描述:类似于数据库表结构 */
  schema?: any;
  /** 初始化数据 */
  model?: any;
  /** 样例数据 */
  sampleData?: any;
  /** 当数据源参数变化时,是否自动刷新数据源数据 */
  autoReload?: boolean;
  /** 当数据源初始化完成后,是否加载数据,设置为true,则不加载,由用户自行加载数据 */
  lazy?: boolean;
  /** 如果配置了启动查询的条件,当前仅当fetchWhen条件为真时才获取数据 */
  fetchWhen?: string;
  /** 实验性属性:数据源依赖的数据源ID集合 */
  dependencies?: string[];

  /** axios配置项 */
  url?: string;
  method?: Method;
  params?: any;
  data?: any;
  headers?: any;
  /** 其他axios配置项 */
  requestConfig?: AxiosRequestConfig;
  /** 自定义查询结果转换函数:可以指定为页面函数 */
  responseMapperType?: string;
}

# 页面函数(functions)

页面函数,用来定义一些复杂的操作函数,下面是一个简单的示例:

{
  "type": "AdaptivePage",
  "version": "2.0",
  "functions": {
    "transformed": false,
    "script": "export function camelCase(str){ return _.camelCase(str);}; export function camelCase2(str){ return _.camelCase(str);};\n    export function camelCase3(str){ return _.camelCase(str);}"
  },
  "body": [
    {
      "type": "Card",
      "props": {
        "title": "",
        "shadow": true
      },
      "children": [
        {
          "type": "LcdpHtml",
          "props": {
            "content": "${camelCase(\"oh-my-god\")}"
          },
          "style": "display:block"
        }
      ]
    }
  ]
}

# 页面事件(events)

页面事件,用来定义一些页面级别的事件,例如页面加载后执行事件:

{
  "events": {
    "on-rendered": {
      "actions": [
        {
          "type": "Action.SetPageVariable",
          "inputs": {
            "variables": [
              {
                "name": "keyword",
                "value": "abc"
              }
            ]
          }
        }
      ]
    }
  }
}

# 页面子项(组件)

# 属性(props)

通过 props 来定义组件的属性。支持 html 原生属性 style、class、id 以及 可见性属性 visible,这些是公共的属性,不需要在组件的 schema 的 props 定义,因此在运行时它们都位于组件运行时 json 的顶级:

{
  "body": [
    {
      "type": "", //组件类型ID
      "id": "", //组件唯一ID
      "visible": true, //是否可见
      "props": {
        "p1": "abc",
        "p2": "cde"
      },
      "style": "", //html属性:style
      "class": "" //html属性:class
    }
  ]
}

# 事件(events)

组件的 events 支持两种模式,一种是简单模式,actions 是个数组,数组中的操作按顺序执行

{
  "body": [
    {
      "type": "Select",
      "props": {
        "value": "${selectedOption1}",
        "labelInValue": true,
        "placeholder": "请选择选项值"
      },
      "events": {
        //事件ID
        "on-change": {
          //固定为actions
          "actions": [
            {
              "type": "Action.SetPageVariable", //操作类型ID
              //操作的输入参数定义
              "inputs": {
                "variables": [
                  {
                    "name": "selectedOptionLabel2",
                    "value": "${$event.label}"
                  }
                ]
              }
            }
          ]
        }
      }
    }
  ]
}

另一种为编排模式,事件由编排 ID 对应的编排来定义,使用编排 ID 是为了分离编排设计器时定义(可保存在任意存储中由 ID 标记)和页面的运行时页面定义 orchestrations 部分:

{
  "type": "AdaptivePage",
  "version": "2.0",
  "body": [
    {
      "type": "Select",
      "props": {
        "value": "${selectedOption1}",
        "labelInValue": true,
        "placeholder": "请选择选项值"
      },
      "events": {
        //事件on-change的操作由编排ID为orch-2的编排定义
        //这里用编排ID,是为了分离编排设计器时定义(可保存在任意存储中由ID标记)和页面的运行时定义orchestrations部分
        "on-change": "orch-2"
      }
    }
  ],
  //页面所有编排定义
  "orchestrations": {
    "orch-2": {
      "actions": {
        "1": {
          "type": "Action.SetPageVariable",
          "inputs": {
            "variables": [
              {
                "name": "selectedOptionLabel",
                "value": "${$event.label}"
              }
            ]
          },
          "next": ["end"]
        },
        "start": {
          "type": "Action.Start",
          "next": "1"
        },
        "end": {
          "type": "Action.End",
          "next": null
        }
      }
    }
  }
}

# 插槽(slots)

组件的插槽部分用 slots 表示

{
  "type": "AdaptivePage",
  "version": "2.0",
  "body": [
    {
      "type": "CustCom",
      "props": {
        "title": "含插槽组件",
        "shadow": false,
        "icon": "ios-alarm-outline"
      },
      "slots": {
        "slot1": {
          "context": {
            "name": "slotProps" //传递给插槽的范围参数名称
          },
          "children": [
            {
              "type": "Icon",
              "props": {
                "type": "ios-checkmark",
                "size": "24",
                "color": "green"
              }
            },
            {
              "type": "LcdpHtml",
              "props": {
                "content": "保存"
              }
            }
          ]
        }
      }
    }
  ]
}

# 循环(loop)

组件循环用来循环渲染某个组件

{
  "type": "AdaptivePage",
  "version": "2.0",
  "body": [
    {
      "type": "Card",
      "props": {
        "title": "循环卡片1",
        "shadow": true
      },
      "children": [
        {
          "type": "LcdpHtml",
          "loop": {
            "data": [1, 2, 3],
            "variableName": "item",
            "indexName": "index",
            "key": "",
            //可指定context.name来给子组件的事件操作中附加当前循环loopContext1,从而在操作中可以使用loopContext1
            "context": {
              "name": "loopContext1"
            }
          },
          "props": {
            "content": "${index+\" - \"+item}"
          },
          "style": "display:block"
        }
      ]
    },
    {
      "type": "Card",
      "props": {
        "title": "循环卡片2",
        "shadow": true
      },
      "children": [
        {
          "type": "LcdpHtml",
          "loop": {
            "data": "${users}",
            "variableName": "item",
            "indexName": "index",
            "key": "${item.id}"
          },
          "props": {
            "content": "${index+\" - \"+item.name}"
          },
          "style": "display:block"
        }
      ]
    }
  ],
  "variables": {
    "users": {
      "title": "用户",
      "type": "array",
      "default": [
        {
          "id": "1",
          "name": "王波"
        },
        {
          "id": "2",
          "name": "刘海"
        }
      ]
    }
  }
}

# 页面样式(style class)

页面样式和 class 用来定义页面的样式和 class

{
  "style": "background-color: #f0f2f5;",
  "class": "fly-m-md "
}

# 页面交互编排(orchestrations)

对于组合动作,交互编排是必不可少的,它是一个对象,对象中包含了多个动作,每个动作是一个对象,对象中包含了动作的配置信息,例如:type、inputs、next 等。以下是一个简单的页面交互动作编排结构示例:

{
  "orchestrations": {
    "Ue8r2m0dyY": {  //编排ID
      "actions": {
        "start": {
          "type": "Action.Start",
          "inputs": {},
          "next": "action-82"
        },
        "action-82": {
          "type": "Action.SetPageVariable",
          "inputs": {
            "variables": []
          },
          "next": "end"
        },
        "end": {
          "type": "Action.End",
          "inputs": {},
          "next": null
        }
      }
    }
  }
}
顶部