后端视图扩展

在开发中,常常需要对已有的视图进行扩展,例如增加字段、添加标签页等。以下是一个详细的示例和说明,展示如何通过 JSONPath 对视图进行扩展。

1. 语法示例

{
	"jsonpath": [
		{
			"has_not": "tars",
			"expr": "tbar.打印",
			"position": "after",
			"body": [
				{
					"action": "create",
					"auth": "create",
					"name": "无单据生成",
					"actionAfter": "refreshTable"
				}
			]
		},
		{
			"expr": "columns.repairDate",
			"position": "before",
			"body": [
				{
					"displayName": "报修单号2扩展",
					"name": "reportNo2",
					"groupConf": {
						"name": "故障信息",
						"id": "repairInfoGroup"
					}
				}
			]
		},
		{
			"expr": "buttons.编辑",
			"position": "before",
			"body": [
				{
					"action": "delete",
					"auth": "delete",
					"name": "删除"
				}
			]
		}
	]
}

语法介绍

  • has_not: 判断某个字段或属性是否存在。如果不存在,则执行创建属性。
  • expr: 指定要扩展的位置,支持简略语法:
    • columns.namebuttons.nametbar.name:通过 name 属性定位。
    • 示例:tabs[?(@.name=='item_info_tab')]..columns.desc
  • position: 指定插入位置,可选值:
    • after:插入在指定位置之后。
    • before:插入在指定位置之前。
    • replace:替换内容。
    • attributes:添加属性。
  • body: 扩展的内容,可以是字段、按钮、标签页等。

2. 编写 A 视图

声明菜单,view 指定视图的类型

"mom_material_menu": {
	"name": "mom_material_menu",
	"display_name": "物料",
	"model": "Material",
	"view": "material_grid,material_search,material_form",
	"sequence": 2,
	"active": true,
	"parent_ids": {
		"@ref": "mom_config_menu"
	}
}

2.1 声明 A 的表单视图,这里定义了一个标签页

{
    "material_form": {
        "body": {
            "columns": [],
            "tabs": [
                {
                    "header": "基本资料",
                    "rowspan": 1,
                    "name": "item_info_tab",
                    "body": {
                        "type": "formPart",
                        "model": "Material",
                        "columns": []
                    }
                }
                {
                    "header": "设计资料",
                    "rowspan": 1,
                    "name": "item_design_info_tab",
                    "body": {
                      "type": "formPart",
                      "model": "Material",
                      "columns": [
                      ]
                    }
                  }
            ],
            "type": "form"
        },
        "mode": "primary",
        "model": "Material",
        "name": "物料-表单",
        "type": "form"
    }
}

2.2 在B app声明扩展视图

{
  "views": {
    "aps_buyer_tab_form_ext": {
      "name": "mom-item扩展-采购资料tab",
      "model": "Material",
      "type": "form",
      "mode": "extension", # 填扩展类型
      "inherit_ids": {
        "@ref": "siemes.material_form" # 指定对应 siemes app 要扩展的视图
      },
      "body": {
        "jsonpath": [
          {
            "expr": "tabs[?(@.name=='item_info_tab')]..columns.desc", # 扩展的位置,通过 name 找到 tab 里面的字段
            "position": "before", # 扩展的位置
            "body": [
              "zhichengluxiam" # 扩展的内容,新增一个字段
            ]
          },
          {
            "expr": "tabs[?(@.name=='item_info_tab')]..columns.shengchantiqianqi",
            "position": "after",
            "body": [
              "gongyicanshufenlei"
            ]
          },
          {
            "has_not": "tabs", # 判断是否有 tabs
            "expr": "tabs[?(@.name=='item_design_info_tab')]", # 找到指定的 tab
            "position": "after",
            "body": [ # 扩展的内容
              {
                "header": "采购资料",
                "body": {
                  "type": "formPart",
                  "model": "Material",
                  "columns": [
                    "caigouziliao",
                    "caigouyuan",
                    "caigoutiqianqi"
                  ]
                }
              }
            ]
          }
        ]
      }
    }
  }
}

3. 示例:

  1. 扩展表单,给表单的一个字段后面新增一个字段
  2. 给表单的tab页新增一个字段
    {
    	"views": {
    		"test_eam_fault_maintenance_order_form_ext": {
    			"mode": "extension",
    			"inherit_ids": {
    				"@ref": "newSdkApp.test_eam_fault_maintenance_order_form"
    			},
    			"model": "test_eam_fault_maintenance_order",
    			"name": "故障工单-表单",
    			"type": "form",
    			"body": {
    				"jsonpath": [
    					{
    						"expr": "columns.repairDate",
    						"position": "after",
    						"body": [
    							{
    								"displayName": "报修单号2扩展",
    								"name": "reportNo2",
    								"groupConf": {
    									"name": "故障信息",
    									"id": "repairInfoGroup"
    								}
    							}
    						]
    					},
    					{
    						"expr": "tabs[?(@.name=='maintenanceInformationTab')]..columns.responseTime",
    						"position": "after",
    						"body": [
    							{
    								"displayName": "报修单号acceptedBy扩展",
    								"name": "reportNo2"
    							}
    						]
    					}
    				]
    			}
    		}
    	}
    }
    

4. 常用 expr 示例

  • 新增一个字段

    {
      "expr": "columns.fieldName",
      "position": "after",
      "body": [
        {
          "name": "newField",
          "displayName": "新字段"
        }
      ]
    }
  • 替换一个字段

    {
      "expr": "columns.fieldName",
      "position": "replace",
      "body": [
        {
          "name": "replacedField",
          "displayName": "替换字段"
        }
      ]
    }
  • 新增一个按钮

    {
      "expr": "buttons.删除",
      "position": "after",
      "body": [
        {
          "name": "newButton",
          "displayName": "新按钮"
        }
      ]
    }
  • 新增一个标签页

    {
    			"has_not": "tabs",
    			"expr": "tabs[?(@.name=='item_design_info_tab')]",
    			"position": "after",
    			"body": [
    				{
    					"header": "采购资料",
    					"body": {
    						"type": "formPart",
    						"model": "Material",
    						"columns": [
    							"caigouziliao",
    							"caigouyuan",
    							"caigoutiqianqi"
    						]
    					}
    				}
    			]
    }
  • 追加一个标签页里面的按钮(之前的tab已存在tbar)

    {
    	"has_not": "tabs",
    	"expr": "$..tabs[?(@.name == 'mbm_wms_dispatch_order_menu_tab_allocation_detail_list')]..tbar",
    	"position": "inside",
    	"body": [
    		{
    			"name": "桶仓收货开启",
              "service": "siloDelivery",
              "auth": "siloDelivery",
              "action": "siloDelivery",
              "isLoading": true
    		}
    	]
    }

    5. JsonPath语法

JsonPath的语法相对简单,它采用开发语言友好的表达式形式,如果你了解类C语言,对JsonPath就不会感到不适应。 JsonPath语法要点:

  • $ 表示文档的根元素
  • @ 表示文档的当前元素
  • .node_name['node_name'] 匹配下级节点
  • [index] 检索数组中的元素
  • [start:end:step] 支持数组切片语法
  • * 作为通配符,匹配所有成员
  • .. 子递归通配符,匹配成员的所有子元素
  • (<expr>) 使用表达式
  • ?(<boolean expr>)进行数据筛选

下表将列举所有支持的语法,并对XPath进行比较:

XPath JsonPath 说明
/ $ 文档根元素
. @ 当前元素
/ .[] 匹配下级元素
.. N/A 匹配上级元素,JsonPath不支持此操作符
// .. 递归匹配所有子元素
* * 通配符,匹配下级元素
@ N/A 匹配属性,JsonPath不支持此操作符
[] [] 下标运算符,根据索引获取元素,XPath索引从1开始,JsonPath索引从0开始
| [,] 连接操作符,将多个结果拼接成数组返回,可以使用索引或别名
N/A [start:end:step] 数据切片操作,XPath不支持
[] ?() 过滤表达式
N/A () 脚本表达式,使用底层脚本引擎,XPath不支持
() N/A 分组,JsonPath不支持

注意:

  • JsonPath的索引从0开始计数
  • JsonPath中字符串使用单引号表示,例如:$.store.book[?(@.category=='reference')]中的'reference'

JsonPath示例

下面是相应的JsonPath的示例,代码来源于https://goessner.net/articles/JsonPath/,JSON文档如下:

{
    "store": {
        "book": [{
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            }, {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            }, {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            }, {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    }
}

接下来我们看一下如何对这个文档进行解析:

XPath JsonPath Result
/store/book/author $.store.book[*].author 所有book的author节点
//author $..author 所有author节点
/store/* $.store.* store下的所有节点,book数组和bicycle节点
/store//price $.store..price store下的所有price节点
//book[3] $..book[2] 匹配第3个book节点
//book[last()] $..book[(@.length-1)],或 $..book[-1:] 匹配倒数第1个book节点
//book[position()<3] $..book[0,1],或 $..book[:2] 匹配前两个book节点
//book[isbn] $..book[?(@.isbn)] 过滤含isbn字段的节点
//book[price<10] $..book[?(@.price<10)] 过滤price<10的节点
//* $..* 递归匹配所有子节点