标准插件的表单项渲染和事件交互,基于事先定义好的 Tag 组件。一个 Tag 组件可以理解为一种类型的表单封装(如 input、textarea、table、upload 等),通过在原生表单元素或者特定业务组件上扩展属性和方法,为标准插件的开发和使用提供了便利。标准插件一般包含一个或者多个 Tag 组件,前端页面加载标准插件配置文件,读取每个表单项的 type 字段,渲染生成对应类型的表单。
标准插件表单项的渲染由 RenderForm 组件分发。RenderForm 组件基于 Vue 封装,利用 Vue 数据双向绑定的特性,实现了组件表单项取值 value 的 v-model 指令,调用组件时只需传入对应的配置项 props,就可以实现父组件与 RenderForm 内部组件的数据自动同步。
配置文件里每一个表单项配置在前端组件渲染底层对应一个 FormItem 组件,一般情况下(非勾选状态),FormItem 组件下都包含一个 Tag* 子组件, Tag 的类型由配置项的 type 字段定义,目前支持的类型包括: input、textarea、checkbox、radio、select、table、upload、tree、password等,所有 Tag 组件都定义了一些公共的属性或者方法,若某种 Tag 类型需要支持的特定事件或者功能,则在对应的 Tag 子组件里定义。如果官方 Tag 不满足自定义开发的插件需要,也可以按照规范自定义开发新的 Tag。
RenderForm 组件的结构:
标准插件表单的渲染流程:
formMixins 函数定义了一些 Tag 组件公共的属性和方法,在添加 Tag 组件调用该方法来混入,可以避免编写重复的声明。
公共属性分为继承属性和非继承属性,继承属性在 Tag 组件里会被定义为 props 属性,目前只有 value 属性,非继承属性会被转换为 data 属性,它的值不会动态更新。属性的值,优先取标准插件配置文件里定义的值,若配置项没有对应属性的默认值。
Tag 组件的私有属性在添加组件时定义,属性的取值和公共属性一致,优先取标准插件配置文件里的值,若配置项没有对应属性则取默认值。
Tag 组件的使用非常简单,只需要在标准插件配置项中定义好 type
字段,传入该类 Tag 支持的属性和方法即可在前端页面渲染出对应的表单项,通过 Tag 组件之间的组合,也可以构造出复杂的表单交互。
目前标准运维系统内置的 Tag 组件包含:
- button
- cascader
- checkbox
- datatable
- datetime
- time
- input
- int
- ipSelector
- password
- radio
- select
- text
- textarea
- tree
- upload
- memberSelector
- setAllocation
- TagSection
- codeEditor
Tag 组件中的所有属性配置都在 attrs
字段里声明。
例如,给 select 组件设置 name 属性为 “业务id”,placeholder 属性设置为 “请选择业务”:
...
attrs: {
name: '业务id',
placeholder: '请选择业务'
}
...
标准插件中定义的配置项在页面渲染时,会作为属性传入到 Tag 组件中。Tag 组件根据不同的属性值,可以灵活的扩展多种表单配置,例如 TagSelect
组件可以通过 multiple
属性来区分下拉框为单选还是多选,TagUpload
组件可以通过 remote_data_init
属性来自定义加载数据后的处理逻辑。
不同的标准插件在前端页面渲染时,存在一些公共的交互逻辑,包括表单项名称、是否隐藏、是否可勾选、是否校验等,这部分属性称为公共属性,所有的 Tag 组件都支持标准插件自定义配置。由于不同 Tag 的都有自己的应用场景,Tag 组件内部封装的原生表单或者特定业务场景的类型差异,不同 Tag 组件之间所支持的属性也会存在差异,只在某种 Tag 组件里支持标准插件自定义配置,这类属性称为私有属性, 比如 TagUpload
组件的 remote_data_init
属性。
为了增加标准插件的能力,Tag 组件也封装了部分公共方法,支持开发者在标准插件配置项的事件回调里进行调用,例如隐藏表单、获取上级表单组件、获取当前表单值等。
配置文件里定义的表单项属性和方法,只有在 Tag 组件里声明过,才能够被组件正确的拿到。
name
:表单项名称,在页面上控制 label 的显示hookable
:是否可勾选为全局变量validation
:表单项的校验规则,表单的校验分三种类型required
、regex
、custom
,根据需求选择使用:
{
// ...
validation: [
{ type: 'required' },
{
type: 'regex',
args: RegExp, //例如 /\d{3}/
error_message: String //例如 '请输入3个数字'
},
{
type: 'custom',
args (value, parentValue) {
//...
return { // 校验方法必须返回如下格式对象
result: Boolean,
error_message: String
}
}
},
]
}
default
:表单项的默认值,不同的 Tag 组件支持的数据类型存在差异hidden
:是否默认隐藏formViewHidden
:查看模式下,表单是否隐藏col
:横向栅格占有的格数,总数为 12 格,设置该属性后,多个表单可横向布局value
:表单组件的值,需要在 Tag 里手动定义,并作为调用getFormMixins
函数的参数传入
updateForm
:触发change
事件更新表单值,并调用校验函数,参数为value
validate
:校验函数show
:表单隐藏hide
:表单显示get_form_instance
:获取表单实例,FormItemget_parent
:获取 combine 实例或根元素实例get_child
:获取表单实例,参数为子表单的 tag_code,支持 RenderForm 或 RenderGroup 组件调用get_value
:获取表单值,其中支持配置传入一个布尔值参数,默认为 false,如果传入参数值为 true,则 tag 表单勾选为全局变量时,可获取对应全局变量的 value 值get_tag_value
: 获取当前标准插件的任一表单值,参数path
为目标 tag 表单的层级,表单值从标准插件最外层开始查找,例如['bk_receiver_info', 'bk_more_receiver']
set_value
:设置表单值,参数为表单值
按钮,一般由其他 Tag 组件监听按钮的 click
事件, 用来实现 Tag 组件间的交互。
属性
title
:按钮文字type
:按钮类型,取值范围:default、primary、warning、success、dangericon
:icon 类名, 取值参考 蓝鲸 iconsize
:尺寸,取值范围:small、normal、largedisabled
:是否禁用,禁用后按钮点击事件不生效loading
:是否加载中,加载过程中按钮点击事件不生效text
:是否是文字按钮
方法
none
级联组件,一般用于逐级查看和选择多层级结构的数据。
属性
items
::提供选择的级联选项,eg: [{label: '', value: '', children: [...]}, {label: '', value: '', children: [...]}]value
:级联选择器的选中值disabled
:设置是否禁用组件multiple
:设置是否可多选filterable
:设置是否可搜索placeholder
:占位文本lazy
:是否开启远程加载lazyLoad
:远程加载方法, 文档参考element-ui cascader组件lazyload说明
方法
none
多选框,通过配置项传入可选项,提供给使用者选择。
属性
items
:提供选择的多选项,eg: [{name: '微信', value: 'weixin'}, {name: '邮件', value: 'mail}]disabled
:设置是否禁用组件value
:选中项的 value
方法
none
表格,用来展示多条并列数据,支持远程加载数据、单独添加数据、数据编辑。
属性
columns
:表格列的配置项,eg: [ { tag_code: "name", type: "text", attrs: { name: gettext("参数名称"), } }, { tag_code: "type", type: "text", attrs: { name: gettext("参数类型"), hidden: true, } }, { tag_code: "value", type: "textarea", attrs: { name: gettext("参数值"), editable: true } } ]editable
:是否显示表格操作列,包含编辑、删除、保存、取消按钮deleteable
:是否显示删除按钮,用来单独控制表格操作列的删除按钮add_btn
: 是否显示添加按钮table_buttons
: 自定义配置表格按钮,eg: [{text: '点击', callback: function(){console.log(1)}, type: 'xxx or import'}, ...],其中 type 为非必需字段,值为 import 时,点击回调使用内置的上传函数empty_text
:无数据提示remote_url
:表格数据远程加载,支持 url 字符串以及返回 url 字符串的方法remote_data_init
:加载数据后的处理函数row_click_handler
: 单行点击回调函数,回调参数如下:- row, eg: { key1:'value1',key2:'value2' }
- column, eg: { label: 'name', property: 'key1' }
- event
row_draggable
:表格行是否可以拖拽pagination
:表格数据分页展示,默认不展示(false)page_size
:表格分页展示时,每页显示的条数(Number),默认 10 条每页value
:表格的值
方法
validateSubCom
:校验表格内的数据是否符合规则(规则由对应的列的标准插件配置项指定)set_loading
:传入布尔类型参数来设置表格是否为 loading 状态remoteMethod
:远程加载数据export2Excel
:将表格数据导出到 excel 文件
日期时间选择器。
属性
placeholder
:占位文本disabled
:设置是否禁用组件type
:日期选择器显示类型,默认为 datetime,可选值包括:date、datetime、datetimerange、daterange 等format
:选中的时间以及展示的值,默认为 yyyy-MM-dd HH:mm:ss,参考日期格式value
:时间值
方法
none
时间选择器。
属性
placeholder
:占位文本startPlaceholder
:开始时间占位文本endPlaceholder
:结束时间占位文本disabled
:设置是否禁用组件isRange
:是否选择时间段format
:选中的时间以及展示的值,默认为 HH:mm:ss,参考日期格式value
:时间值
方法
none
文本框,一般用来输入单行文本。
属性
placeholder
:占位文本min
:最小值,默认为 -Infinitymax
:最大值,默认为 Infinitydisabled
:设置是否禁用组件showPassword
:是否以密码模式显示value
:文本框值
方法
none
整数输入框,用来输入正整数。
属性
placeholder
:占位文本disabled
:设置是否禁用组件value
:整数输入框值
方法
none
ip 选择器,支持静态 ip 或动态 ip 的单选和多选。
属性
isMultiple
:ip 选择器是否为多选(单选为选择静态或者动态 ip,多选为同时选择静态、动态 ip)remote_url
:组件内部调用接口 url 配置,支持对象格式以及返回对象的方法,eg: { cc_search_module: '/pipeline/cc_search_module/2/' }disabled
:设置是否禁用组件value
:选择的 ip 值
方法
none
密码输入框。
属性
pubKey
: 加密公钥disabled
:设置是否禁用组件canUseVar
: 是否可以使用全局变量,默认为truetextareaMode
: 手动输入密码时,表单类型为textarea,默认为falsevalue
:加密后的密码值
方法
none
单选框,通过配置项传入可选项,提供给使用者选择。
属性
items
:提供选择的单选项,eg: [{name: '微信', value: 'weixin'}, {name: '邮件', value: 'mail}]disabled
:设置是否禁用组件value
:选中项的 value
方法
none
下拉框,通过配置项传入可选项,提供给使用者选择,选项支持远程加载。
属性
items
:提供选择的下拉框选项, eg:[{text: '微信', value: 'weixin'}, {text: '邮件', value: 'mail'}]multiple
:是否为多选remote
:是否开远程加载remote_url
: 远程加载 url,支持 url 字符串以及返回 url 字符串的方法remote_data_init
:远程加载后的数据处理函数placeholder
:占位文本empty_text
:无数据提示hasGroup
:选项是否分组clearable
:是否显示右侧清除表单值iconallowCreate
:是否支持输入框创建选项showRightBtn
:是否显示选择框右侧按钮,默认 falserightBtnIcon
:选择框右侧按钮icon,默认 'bk-icon icon-chain'rightBtnCb
:选择框右侧按钮点击回调函数,默认为空disabled
:设置是否禁用组件value
:选中项的 value,多选框的值以英文逗号,
分隔
方法
set_loading
:传入布尔类型参数来设置下拉框是否为 loading 状态remoteMethod
:远程加载数据
文本组件,不可编辑,一般用来展示文本信息。
属性
raw
:是否保留文本的换行符、空格,默认为false
value
:文本的值
方法
none
多行文本框。
属性
placeholder
:占位文本disabled
:设置是否禁用组件value
:文本框的值
方法
none
树形选择组件,一般用来多个分组层级数据的选择。通过配置项传入可选项,提供给使用者选择,选项支持远程加载。
属性
items
:提供选择的可选项,eg:
[
{
label: '通知方式',
children: [
{
label: '信息',
children: [
{ label: '短信' },
{ label: '企业微信' },
{ label: '微信' }
]
},
{ label: '语音' }
]
},
{
label: '通知分组',
children: [
{ label: '运维人员' },
{ label: '产品人员' },
{ label: '开发人员' },
{ label: '测试人员' }
]
}
]
expanded_keys
:默认展开的节点的 key 的数组show_checkbox
:节点是否可被选择default_expand_all
: 是否默认全部展开remote
: 是否开启远程加载remote_url
: 远程加载 url,支持 url 字符串以及返回 url 字符串的方法remote_data_init
:远程加载后的数据处理函数value
:选中的值
方法
remoteMethod
:远程加载数据
上传组件。
属性
url
: 服务器 urlmultiple
:是否支持多个上传headers
:http 请求头data_params
:文件上传附加参数,eg: { filename: 'test.zip', filetype: 'zip' }auto_upload
:是否开启自动上传,默认值为 true,自动上传(选择文件后自动触发上传),手动上传(选择文件后需要点击上传按钮,调用自定义的 submit 方法回调)withCredentials
: 支持发送 cookie 凭证信息submit
:自定义上传方法limit
:上传文件个数placeholder
:占位文本text
:上传按钮的文字disabled
:设置是否禁用组件value
:上传的文件
方法
onSubmit
: 手动上传按钮点击时间回调,默认开始执行上传,若配置项传入submit
属性,则执行该方法httpRequest
: 自定义上传函数,会覆盖默认的上传行为,若需要调用成功、失败回调函数,则需要返回 PromisebeforeUpload
: 上传之前钩子函数,如果需要钩子函数里需要调用异步请求,且依赖请求数据,则需要返回 Promise,若返回 false 或者返回 Promise 且被 reject,则取消上传,参数 filebeforeRemove
: 删除文件之前的钩子函数,若返回 false 或者返回 Promise 且被 reject,则取消删除,参数 file, fileListonSuccess
: 文件上传成功时的钩子函数,参数 file, fileListonRemove
: 文件列表移除文件时的钩子函数,参数 file, fileListfileChange
: 上传文件变更时的钩子函数,添加文件、上传成功和上传失败时都会被调用,参数 file, fileListonError
: 文件上传失败时的钩子函数,参数 err, file, fileList
人员选择组件
属性
placeholder
:占位文本disabled
:设置是否禁用组件value
:选择人员名字,名字间以 ',' 隔开。eg:"xiaoming,xiaozhang,xiaoli"
方法
日志展示
属性
value
:日志内容, \n 表示换行
方法
none
开区资源选择器。
属性
remote_url
:组件内部调用接口 url 配置,支持对象格式以及返回对象的方法,eg: { cc_search_module: '/pipeline/cc_search_module/2/' }disabled
:设置是否禁用组件value
:选择的资源值以及筛选配置
方法
none
标准插件表单分隔 Tag,一般在表单项数量较多时用来做分组区分,配置项的 name 属性值会被渲染为分组名称。
属性
none
方法
none
代码编辑器
属性
value
:代码字符串language
: 编辑器语言,默认为 python,支持 javascript typescript json python shellheight
: 编辑器高度,默认 100pxshowMiniMap
: 显示小地图,默认 falseshowLanguageSwitch
: 显示语言切换,默认 truereadOnly
: 只读模式,默认 falsevariable_render
: 是否开启变量渲染,默认 false
方法
none
Tag 组件在初始化渲染时,会将标准插件对应配置项 methods 属性中的方法注册到 Tag 组件中,标准插件可根据需求添加方法。
若标准插件需要在 Tag 组件初次渲染时,执行一些初始化的逻辑,可在 methods
属性中定义 _tag_init
方法,该方法在组件挂在到页面上会默认执行。
Tag 组件在通过发布/订阅的方式,实现了组件间的事件交互, 例如在 TagSelect 组件里,选择某项数据后,将值更新到与它同级的 TagInput 中。前端渲染组件时,会根据标准插件里 events 属性配置的 source + type 规则来注册定义的事件监听,其他组件可以通过调用 this.$emit(${tagcode}_${event_type})
来触发对应表单的事件监听回调。
Tag 组件间的事件交互使用方式比较简单,只需要在标准插件表单项中定义好 events 规则,即可监听对应表单派发的事件,例如:
tag_code: 'biz_input',
type: 'input',
attrs: {
name: 'some label'
},
events: [
{
source: "biz_info",
type: "change",
action: function () {
const bizInfo = this.get_parent().get_child('biz_info')
const value = bizInfo._get_value()
this.updateForm(value)
}
}
]
biz_input
表单项会监听 biz_info
表单项值的变更事件,将它的选中值更新到 input 中。
Tag 组件在前端初始化渲染时,会默认抛出 init 事件(标准插件 methods 配置项里的定义 _tag_init
方法,在 init 事件抛出之前执行)
Tips
- 每个 Tag 组件在渲染到前端页面时,会默认触发
init
事件,标准插件表单项可根据需求是否监听该事件 - 每个 Tag 组件在表单值发生变更时,会默认触发
change
事件,标准插件表单项可根据需求是否监听该事件 - Tag 组件间只支持同级组件(相同父组件)的事件交互,对应到标准插件配置项中一级表单项或者 combine 里的一级表单项
添加 Tag 组件只需要在前端项目的src/components/tags/
目录里增加一个单文件的 vue 组件,文件名称格式为Tagxxx
,xxx
为 Tag 组件的名称,命名遵循驼峰规则且保证在项目所有Tag
里是唯一的。webpack 在打包时会查找该目录下的文件,自动引入并注册到 FormItem
组件里。模版最外层元素建议增加一个 tag-xxx
的 class
名称,xxx
表示 Tag 的名称。
组件的编写需要注意一下几点:
-
是否展示模式、是否为编辑态
RenderForm 组件为通用组件,标准运维所有页面的标准插件表单渲染都通过使用该组件来实现,页面不同地方可能会区分编辑态、禁用态,表单模式、查看模式,所以在编写组件模版是需要针对不同的场景写不同的模版,编辑、禁用通过
formEdit
属性区分、是否表单模式通过formMode
属性区分。 -
定义私有属性,混入公共属性、方法
编写组件时必须引入公共属性和方法,并且定义好私有属性后调用公共 mixins 函数的参数传入,其中私有属性必须包含 value 属性,属性申明遵循 props 校验规则格式。mixins 函数由前端项目目录
src/components/common/RenderForm/formMixins.js
文件定义。 -
表单值绑定
Tag 组件的值必须实现双向绑定,创建一个计算属性来处理绑定逻辑,计算属性的
get
由 props 里的value
的值(需要注意引用类型值的深拷贝),set
需要调用updateForm
方法传入修改后的value到组件,触发change事件和校验逻辑。