{
  "type": "page",
  "title": "Welcome to Steedos",
  "body": [
    {
      "type": "steedos-object-form",
      "className": "",
      "label": "对象表单",
      "objectApiName": "apps",
      "recordId": "${recordId}",
      "mode": "edit",
      "fieldsExtend": {
        "tab_items": {
          "amis": {
            "name": "tab_items",
            "type": "steedos-input-table",
            "label": "",
            "showIndex": true,
            "source": "${tab_items}",
            "strictMode": true,
            "affixHeader": false,
            "editable": true,
            "addable": false,
            "removable": true,
            "draggable": false,
            "fields": [
              {
                "label": "${'apps.apps_form.tab' | t}",
                "type": "lookup",
                "multiple": false,
                "is_wide": false,
                "required": true,
                "reference_to": "tabs",
                "reference_to_field": "name",
                "sort_no": 30,
                "name": "tab_name",
                "hidden": false,
                "readonly": false,
                "disabled": false,
                "_prefix": "tab_items."
              },
              {
                "label": "${'apps.apps_form.tab_grouping' | t}",
                "name": "group",
                "_prefix": "tab_items.",
                "type": "text",
                "amis": {
                  "type": "select",
                  "source": "${tab_groups|pick:group_name}",
                  "popOverContainerSelector": "body",
                  "onEvent": {
                    "change": {
                      "actions": [
                        {
                          "actionType": "custom",
                          "script": "const tabGroupKey = \"group\";const getTabsSortFun = function (groupNames) {  return function (m, n) {    var tempM = !!m[tabGroupKey] ? 1 : 0;    var tempN = !!n[tabGroupKey] ? 1 : 0;    if (!m[tabGroupKey] || !n[tabGroupKey]) {      return tempM - tempN;    }    return groupNames.indexOf(m[tabGroupKey]) - groupNames.indexOf(n[tabGroupKey]);  };};const quickEidtSaveForTab = function (input, prop_name) {  const currentPropValue = input.value;  const rowValue = input.__super;  const formValue = input.__super.__super;  const tab_name = rowValue.tab_name;  rowValue[prop_name] = currentPropValue;  delete rowValue.index;  let newTabs = formValue.tab_items.map(function (item) {    if (item.tab_name == tab_name) {      return Object.assign({}, item, rowValue);    }    else {      return item;    }  }); const tabGroups = input.__super.__super.tab_groups;  const groupNames = _.compact(_.map(tabGroups, \"group_name\"));  if (groupNames && groupNames.length) {    newTabs.sort(getTabsSortFun(groupNames));  }  return {    tab_items: newTabs  }};const eventData = event.data;const newTabTtemsProp = quickEidtSaveForTab(eventData, \"group\");setTimeout(function () {   doAction({    actionType: 'setValue',    componentId: \"object_form\",    args: {      value: newTabTtemsProp    }  });},300);"
                        }
                      ]
                    }
                  },
                  "placeholder": "-"
                },
                "className": "m-0",
                "checkAll": false,
                "selectFirst": false,
                "searchable": true,
                "clearable": true,
                "multiple": false,
                "mode": "inline"
              }
            ],
            "columns": [
              {
                "name": "tab_name",
                "inlineEditMode": false
              },
              "group"
            ],
            "headerToolbar": [
              {
                "type": "service",
                "id": "tabs-options-service",
                "className": "mb-2",
                "body": [
                  {
                    "type": "button",
                    "id": "u:a35a2276145d",
                    "label": "${'apps.apps_form.tab_generate' | t}",
                    "hidden": true,
                    "onEvent": {
                      "click": {
                        "actions": [
                          {
                            "script": "const appId = null;  const page = Steedos.Page.getPage('app', appId, null, null, 'generate_object_tabs');  if (page && page.schema) {    const pageSchema = JSON.parse(page.schema);    let formSchema = pageSchema.body[0];    formSchema.canAccessSuperData = false;    formSchema.wrapWithPanel = false;    formSchema.className = 'steedos-amis-form';    const title = t('apps.apps_form.tab_generate_title');    doAction({      'actionType': 'dialog',      'dialog': {        'type': 'dialog',        'title': title,        'body': formSchema,        'size': 'lg'      }    });  }",
                            "actionType": "custom"
                          }
                        ],
                        "weight": 0
                      }
                    },
                    "tpl": "内容"
                  },
                  {
                    "type": "button",
                    "label": "${'apps.apps_form.tab_set' | t}",
                    "id": "u:853b890ab524",
                    "actionType": "dialog",
                    "dialog": {
                      "type": "dialog",
                      "title": "${'apps.apps_form.tab_set' | t}",
                      "body": [
                        {
                          "type": "transfer",
                          "name": "picked_tabs",
                          "value": "${tab_items|pick:tab_name}",
                          "sortable": true,
                          "source": "${tabs_options}",
                          "searchable": true,
                          "itemHeight": 40,
                          "id": "u:f2d36873abd1"
                        }
                      ],
                      "onEvent": {
                        "confirm": {
                          "actions": [
                            {
                              "actionType": "custom",
                              "script": "const tabGroupKey = 'group';const getTabsSortFun = function (groupNames) {  return function (m, n) {    var tempM = !!m[tabGroupKey] ? 1 : 0;    var tempN = !!n[tabGroupKey] ? 1 : 0;    if (!m[tabGroupKey] || !n[tabGroupKey]) {      return tempM - tempN;    }    return groupNames.indexOf(m[tabGroupKey]) - groupNames.indexOf(n[tabGroupKey]);  };};const clearTabs = function (input) {   return {    tab_items: []  }};const convertDataForTabs = function (input) {  let pickedTabs = input.picked_tabs || [];   const superTabs = _.keyBy(input.__super.tab_items, 'tab_name');  if (typeof pickedTabs === 'string') {    pickedTabs = pickedTabs.split(',');  } const tabOptions = _.keyBy(input.__super.tabs_options, 'value');  const convertedTabs = pickedTabs.map(function (tab_name) {    const superTab = superTabs[tab_name];    if (superTab) {      return superTab;    }    else {      const tabOption = tabOptions[tab_name];      return {        tab_name: tab_name,        group: tabOption.group      }    }  });  const tabGroups = input.__super.tab_groups;   const groupNames = _.compact(_.map(tabGroups, 'group_name'));   if (groupNames && groupNames.length) {     convertedTabs.sort(getTabsSortFun(groupNames));   }  return {    tab_items: convertedTabs  }};const eventData = event.data;doAction({  actionType: 'setValue',  componentId: 'object_form',  args: {    value: convertDataForTabs(eventData)  }});doAction({  actionType: 'setValue',  componentId: 'tabs-options-service',  args: {    value: convertDataForTabs(eventData)  }});"
                            }
                          ]
                        }
                      },
                      "size": "lg",
                      "id": "u:9c93896a73cf",
                      "closeOnEsc": false,
                      "closeOnOutside": false,
                      "showCloseButton": true,
                      "showErrorMsg": true,
                      "showLoading": true,
                      "dataMapSwitch": false
                    }
                  },
                  {
                    "type": "button",
                    "label": "${'apps.apps_form.tab_grouping_set' | t}",
                    "actionType": "dialog",
                    "dialog": {
                      "title": "${'apps.apps_form.tab_grouping_set' | t}",
                      "body": [
                        {
                          "type": "input-table",
                          "name": "setting_groups",
                          "value": "${tab_groups}",
                          "addable": true,
                          "draggable": true,
                          "editable": true,
                          "needConfirm": false,
                          "columns": [
                            {
                              "name": "group_name",
                              "label": "${'apps.apps_form.tab_grouping_name' | t}",
                              "id": "u:383c7744b499"
                            },
                            {
                              "name": "default_open",
                              "label": "${'apps.apps_form.tab_grouping_open' | t}",
                              "id": "u:7a243c84ed66",
                              "type": "checkbox",
                              "value": true
                            }
                          ],
                          "removable": true,
                          "id": "setting_groups"
                        }
                      ],
                      "onEvent": {
                        "confirm": {
                          "actions": [
                            {
                              "actionType": "custom",
                              "script": "const tabGroupKey = 'group';\nconst getTabsSortFun = function (groupNames) {\n  return function (m, n) {\n    var tempM = !!m[tabGroupKey] ? 1 : 0;\n    var tempN = !!n[tabGroupKey] ? 1 : 0;\n    if (!m[tabGroupKey] || !n[tabGroupKey]) {\n      return tempM - tempN;\n    }\n    return groupNames.indexOf(m[tabGroupKey]) - groupNames.indexOf(n[tabGroupKey]);\n  };\n};\nconst clearTabs = function (input) { return { tab_items: [] } };\nconst convertDataForGroups = function (input) {\n \n  const settingGroups = input.setting_groups || [];\n  const convertedGroups = _.uniqBy(settingGroups.map(function (item) {\n    return { group_name: item.group_name, default_open: item.default_open }\n  }), 'group_name');\n  const groupNames = _.compact(_.map(convertedGroups, 'group_name'));\n  const tab_items = input.tab_items;\n  tab_items?.sort(getTabsSortFun(groupNames));\n  \n  return { tab_groups: convertedGroups, tab_items: tab_items }\n};\nconst eventData = event.data;\ndoAction(\n  {\n    actionType: 'setValue',\n    componentId: 'object_form',\n    args: { value: convertDataForGroups(eventData) }\n  }\n);"
                            }
                          ]
                        }
                      },
                      "type": "dialog",
                      "size": "lg",
                      "id": "setting_groups",
                      "closeOnEsc": false,
                      "closeOnOutside": false,
                      "showCloseButton": true,
                      "showErrorMsg": true,
                      "showLoading": true,
                      "dataMapSwitch": false
                    },
                    "id": "u:111b043b193c"
                  }
                ],
                "messages": {
                },
                "api": {
                  "method": "post",
                  "url": "${context.rootUrl}/graphql",
                  "adaptor": "let data = payload.data;\ndata.tabs_options = [];\nif (data.options && data.options.length) {\n  data.tabs_options = data.options.map(function (option) {\n    option.label = option.label + '(' + option.value + ')';\n    return option;\n  });\n}\nif (!api.body.recordId) {\n  const defaultValues = {\n    is_creator: true,\n    mobile: true,\n    visible: true,\n    sort: 9100\n  };\n  data = Object.assign({}, data, defaultValues);\n}\ndelete data.options;\npayload.data = data;\nreturn payload;  ",
                  "data": {
                    "query": "{options:tabs{_id label:label value:name,type,object,desktop,mobile}}",
                    "recordId": "${recordId}"
                  },
                  "headers": {
                    "Authorization": "Bearer ${context.tenantId},${context.authToken}"
                  },
                  "messages": {
                  },
                  "requestAdaptor": ""
                }
              }
            ],
            "enableDialog": false,
            "id": "u:7949aecf0ca9"
          }
        },
        "objects": {
          "amis": {
            "name": "objects",
            "type": "select",
            "className": "m-0",
            "labelClassName": "text-left",
            "id": "u:4e5047e44905",
            "joinValues": false,
            "extractValue": true,
            "labelField": "label",
            "valueField": "value",
            "multiple": true,
            "checkAll": false,
            "searchable": true,
            "menuTpl": "",
            "source": {
              "method": "get",
              "url": "${context.rootUrl}/service/api/amis-metadata-objects/objects/options",
              "headers": {
                "Authorization": "Bearer ${context.tenantId},${context.authToken}"
              }
            },
            "autoComplete": ""
          }
        },
        "mobile_objects": {
          "amis": {
            "name": "mobile_objects",
            "type": "select",
            "className": "m-0",
            "labelClassName": "text-left",
            "id": "u:cfaeb2f857a8",
            "joinValues": false,
            "extractValue": true,
            "labelField": "label",
            "valueField": "value",
            "multiple": true,
            "checkAll": false,
            "searchable": true,
            "menuTpl": "",
            "source": {
              "method": "get",
              "url": "${context.rootUrl}/service/api/amis-metadata-objects/objects/options",
              "messages": {
              },
              "headers": {
                "Authorization": "Bearer ${context.tenantId},${context.authToken}"
              }
            },
            "autoComplete": ""
          }
        },
        "visible_on": {
          "amis": {
            "type": "control",
            "body": [
              {
                "type": "service",
                "id": "u:edcd865de7d8",
                "body": [
                  {
                    "type": "input-formula",
                    "name": "visible_on",
                    "evalMode": false,
                    "variableMode": "tabs",
                    "variables": "${visibleOnVariables}",
                    "visibleOn": "${visibleOnVariables}",
                    "id": "u:618105d5bfad",
                    "labelClassName": "none"
                  }
                ],
                "api": {
                  "method": "get",
                  "url": "${context.rootUrl}/service/api/amis-metadata-objects/objects/apps/fields/options",
                  "cache": 30000,
                  "adaptor": "const visibleOnVariables = SteedosUI.getFormulaVariables(payload.data.options);\nconst defaultValueVariables = [visibleOnVariables[1]];\npayload = {\n  data: {\n    visibleOnVariables,\n    defaultValueVariables\n  }\n};\nreturn payload;",
                  "headers": {
                    "Authorization": "Bearer ${context.tenantId},${context.authToken}"
                  }
                },
                "dsType": "api"
              }
            ],
            "id": "u:996ef29c6851"
          }
        }
      },
      "enableTabs": true,
      "debug": false,
      "initApiRequestAdaptor": "",
      "initApiAdaptor": "var data = payload.data;\nif (data.tab_items && !_.isArray(data.tab_items)) {\n    // 数据库中存储的是对象格式而不是数组，转换为数组用于界面显示\n    let arrTabItems = [];\n    _.each(data.tab_items, function (n, k) {\n        n.tab_name = k;\n        delete n.index;\n        arrTabItems.push(n);\n    });\n    data.tab_items = arrTabItems;\n}\nif (data._id && !data.tab_items) {\n    const tabOptions = data.tabs_options || [];\n    const tabItems = [];\n    // 把应用中原来tabs属性值添加到新的tab_items属性的默认值中\n    if (data.tabs && data.tabs.length) {\n        data.tabs.forEach(function (item) {\n            tabItems.push({ tab_name: item });\n        });\n    }\n    const pushObjectsToTabItems = function (objects) {\n        objects.forEach(function (item) {\n            // 已经有绑定到指定对象的选项卡就不添加\n            let existObjectItem = !!tabItems.find(function (tabItem) {\n                return !!tabOptions.find(function (option) {\n                    return tabItem.tab_name === tabItem.value && option.object === item;\n                });\n            });\n            if (existObjectItem) {\n                return;\n            }\n            // 找到指向指定对象的选项卡\n            let tempOption = tabOptions.find(function (option) {\n                return option.type === \"object\" && option.object === item;\n            });\n            if (!tempOption) {\n                return;\n            }\n            // 选项卡名称如果重复了就不添加\n            let existTabItem = !!tabItems.find(function (tabItem) {\n                return tabItem.tab_name === tempOption.value;\n            });\n            if (existTabItem) {\n                return;\n            }\n            if (tempOption) {\n                tabItems.push({ tab_name: tempOption.value });\n            }\n        });\n    }\n    // 把应用中原来objects属性值添加到新的tab_items属性的默认值中\n    if (data.objects && data.objects.length) {\n        pushObjectsToTabItems(data.objects);\n    }\n    // 把应用中原来mobile_objects属性值添加到新的tab_items属性的默认值中\n    if (data.mobile_objects && data.mobile_objects.length) {\n        pushObjectsToTabItems(data.mobile_objects);\n    }\n    data.tab_items = tabItems;\n}\n\npayload.data = data;\ndelete payload.extensions;\nreturn payload;\n        ",
      "apiRequestAdaptor": "delete formData.tabs_options;\nconst recordId = formData.recordId;\n\n// 新加字段tab_items，值同步回传到老字段tabs中兼容老UI界面\nformData.tabs = [];\nif (formData.tab_items && formData.tab_items.length) { \n    formData.tabs = formData.tab_items.map(function (item) { return item.tab_name; });\n}\n\n/*\ntab_items存储为：\ntab_items: {\n  test1:{\n    group:\"xxx\"\n  },\n  test3:{\n    group:\"yyy\"\n  }\n}\n而不是：\ntab_items: [\n  {\n    \"index\":1,\n    \"group\":\"xxx\"\n  },\n  {\n    \"index\":2,\n    \"group\":\"yyy\"\n  }\n]\n*/\nif (formData.tab_items) { \n    formData.tab_items = _.keyBy(formData.tab_items, \"tab_name\")\n    let tempIndex = 0;\n    _.each(formData.tab_items, function (n, k) {\n      tempIndex++;\n      n.index = tempIndex;\n      delete n.tab_name;\n    });\n}\n\nquery = `mutation{record: ${objectName}__insert(doc: {__saveData}){_id}}`;\nif(recordId){\n    query = `mutation{record: ${objectName}__update(id: \"${recordId}\", doc: {__saveData}){_id}}`;\n};\n__saveData = JSON.stringify(JSON.stringify(formData));\n\napi.data = {query: query.replace('{__saveData}', __saveData)};\nreturn api;\n",
      "apiAdaptor": "",
      "form": {
        "id": "object_form"
      },
      "id": "u:e1c1a841d373",
      "tabsMode": "line"
    }
  ],
  "regions": [
    "body"
  ],
  "data": {
    "objectName": "apps",
    "initialValues": {},
    "appId": "builder",
    "title": "",
    "context": {
    }
  },
  "id": "u:de840f3523f2"
}