# 新建编辑页JS插件

表单js插件可以非常容易地、无侵入地扩展表单功能。

新建编辑页JS插件包含以下扩展场景:

  • 修改视图展示(自定义字段组件、自定义表单和从对象表格按钮、修改字段的视图状态)
  • 控制表单流程(渲染表单、保存数据、数据校验、计算等)
  • 拦截业务行为(表单按钮点击、字段值变更、从对象按钮点击等)

# 扩展钩子

# entry

用法:

该钩子用来匹配字段,指定哪些字段可以被插件重新定义。需要配合 render 使用。

参数:

  • context: Object:字段的上下文环境
  • field: Object:字段描述信息

示例:

// 通过字段api_name判断
export default {
    entry(context, field) {
        return field.api_name === 'field_bbbb__c';
    }
}
// 通过字段类型判断
export default {
    entry(context, field) {
        return field.type === 'text';
    }
}

# render

用法:

视图渲染函数,定义如何渲染匹配到的字段。字段初次渲染和表单数据模型值发生变更,都会触发该钩子执行。需要配合 entry 使用。

参数:

  • context: Object:字段的上下文环境
  • field: Object:字段描述信息
  • value: *:字段的值
  • wrapper: Object:渲染的容器DOM

返回:

可以返回渲染后的DOM字符串或者DOM对象,也可以不返回。

示例:

// 返回dom对象
export default {
    render(context, field, value) {
        var vm = new Vue({
            render: h => h('div', 'hello fxiaoke')
        }).$mount();
        return vm.$el;
    }
}
// 不返回结果
export default {
    render(context, field, value, wrapper) {
        var vm = new Vue({
            render: h => h('div', 'hello fxiaoke')
        }).$mount();
        wrapper.appendChild(vm.$el);
    }
}

# beforeRender

用法:

beforeRender发生在解析数据之后,渲染视图之前。

参数:

  • context: Object:字段的上下文环境

返回:

  • promise: Promise:无需传递数据。如果不返回,则阻塞后续的流程。

示例:

export default {
    ...
    beforeRender(context) {
        // todo what you want

        return new Promise(function() {
            resolve()
        });
    },
    ...
}

# rendered

用法:

rendered发生在渲染视图之后。

参数:

  • context: Object:字段的上下文环境

返回:

  • promise: Promise:无需传递数据。如果不返回,则阻塞后续的流程。

示例:

export default {
    ...
    rendered(context) {
        // todo what you want

        return new Promise(function() {
            resolve()
        });
    },
    ...
}

# beforeSubmit

用法:

beforeSubmit发生在保存数据之前。

参数:

  • context: Object:字段的上下文环境
  • postData: Object:表单保存时需要提交的数据

返回:

  • promise: Promise:promise的值为处理后的数据。如果不返回,则阻塞后续的流程。

示例:

export default {
    ...
    beforeSubmit: function(context, postData) {
        // todo what you want

        return new Promise(resolve => {
            resolve(postData)
        });
    },
    ...
}

# getTitle

用法:

该钩子用来定义表单标题。

参数:

  • context: Object:字段的上下文环境
  • data: Object:数据
    • data.isEdit: Boolean:是否是编辑

返回:

  • title: String:表单组件的标题。

示例:

export default {
    ...
    getTitle(context, opts) {
        return opts.isEdit ? '编辑' : '新建';
    },
    ...
}

# getButtons

用法:

该钩子用来重置表单的按钮。

参数:

  • context: Object:字段的上下文环境

返回:

  • buttons: Array|Object:定义按钮的修改规则。如果返回数组,则为新增按钮。如果返回对象,则定义按钮的增删改。

示例:

    ...
    getButtons(context) {
        return [{
			action: 'form_button_1',
			label: '自定义按钮1',
			callback(ct) {
				alert('form_button_1');
			}
		},{
			action: 'form_button_2',
			label: '自定义按钮2'
		}]
    },

    // or

    getButtons(context) {
        return {
            add: [{
                action: 'form_button_1',
                label: '自定义按钮1',
                callback(ct) {
                    alert('form_button_1');
                }
            },{
                action: 'form_button_2',
                label: '自定义按钮2'
            }],
            reset: [{
                action: 'form_button_3',
                label: '自定义按钮3'
            }],
            del: ['cancel']
        }
    },
    ...

说明:

  1. add:定义新增按钮
  2. reset:定义重置按钮,可以重置按钮名称和点击行为
  3. del:删除预制按钮

# getMdButtons

用法:

该钩子用来重置从对象表格的按钮。

参数:

  • context: Object:字段的上下文环境
  • detailObjectApiName: String:从对象的apiName

返回:

  • buttons: Object:定义按钮的修改规则。

示例:

    ...
    getMdButtons(context, detailObjectApiName) {
        return return detailObjectApiName === 'object_5Xnrv__c' ? {
            add: [{
            	label: '从对象按钮(添加数据)',
            	action: 'test_handle_1',
            	callBack() {
            		console.log('getMdButtons.button');
					context.addDetailData('object_n8q24__c', 'default__c', [{
                        name: 123,
                    }])
            	}
            }],
            reset: {
				Single_Add: {
					label: '添加数据'
				}
			}
        }:{
            // del: ['Single_Add'],
            'default__c': {
				add: [{
                    label: '从对象按钮(添加)(无callback)',
                    action: 'addMdData'
                },{
                    label: '从对象按钮(删除)(无callback)',
                    action: 'delMdData'
                },{
                    label: '从对象按钮(修改)(无callback)',
                    action: 'updateMdData'
                }]
			}
        }
    },
    ...

说明:

  1. add:声明新增按钮
  2. reset:声明重置按钮,可以重置按钮名称和点击行为
  3. del:声明删除的按钮
  4. default__c:声明给哪个业务类型定义按钮

# getMdOperateButtons

用法:

该钩子用来重置从对象单行数据的操作按钮。

参数:

  • context: Object:字段的上下文环境
  • detailObjectApiName: String:从对象的apiName

返回:

  • buttons: Array:定义按钮的修改规则。

示例:

    ...
    getMdOperateButtons(context, detailObjectApiName) {
		console.log('getMdOperateButtons', arguments);
		return detailObjectApiName === 'object_n8q24__c' ? [function() {
        	return {
        		add: [{
        			label: '自定义操作按钮',
        			action: 'test_handle_3',
					callBack() {
						console.log('test_handle_3');
					}
        		}]
        	}
        }] : []
	}
    ...

说明:

  1. add:声明新增按钮
  2. 单行操作按钮仅支持增加按钮,不支持删除、定义重置按钮

# getMdBatchButtons

用法:

该钩子用来重置从对象表格批量操作按钮。

参数:

  • context: Object:字段的上下文环境
  • detailObjectApiName: String:从对象的apiName

返回:

  • buttons: Object:定义按钮的修改规则。

示例:

    ...
    getMdBatchButtons(context, detailObjectApiName) {
		console.log('getMdBatchButtons', arguments);
		return detailObjectApiName === 'object_n8q24__c' ? {
        	add: [{
        		label: '自定义批量按钮',
        		action: 'test_handle_4',
                callBack() {
                	alert(arguments)
                }
        	}]
        } : {}
	},
    ...

说明:

  1. add:声明新增按钮
  2. 批量操作按钮仅支持增加按钮,不支持删除、定义重置按钮

# 以上三个从对象按钮重置规则说明

说明:

方法 说明 参数 参数内参数格式及说明 crm表格从对象按钮格式
getMdButtons.add 添加按钮 Array Object:label、action、callback(可选) Object:label、action、name
getMdButtons.reset 修改按钮 Object Object(name):label Object:label、action、name
getMdButtons.del 删除按钮 Array String(对应按钮的name) Object:label、action、name
getMdOperateButtons 仅支持添加按钮 Object Object:label、action、callback(可选) Object:label、action
getMdBatchButtons 仅支持添加按钮 Object Object:label、action、callback(可选) Object:label、action

# getMdColumnRenders

用法:

该钩子用来定义从对象上的布局规则。

参数:

  • context: Object:字段的上下文环境
  • detailObjectApiName: String:从对象的apiName

返回:

  • rules: Object:从对象布局规则

示例:

export default {
    ...
    getMdColumnRenders(context, detailObjectApiName) {
        const rules = {
            object_adlkjd__c: {
                field_dlkjdd__c: {
                    depend_fields: ['field_aaaaa__c', 'field_bbbbb__c'],
                    render(val, data) {
                        return '<div>...</div>'
                    }
                }
            }
        }
        return rules;
    },
    ...
}

说明:

  1. object_adlkjd__c:为从对象的apiName
  2. field_dlkjdd__c:从对象的字段
  3. depend_fields:声明field_dlkjdd__c受哪些字段影响
  4. render:定义展示的内容

# getMdImportConfig

用法:

该钩子用来定义导入从对象的相关配置:格式化导入的数据。

参数:

  • context: Object:字段的上下文环境

返回:

  • config: Object:导入从对象配置
    • filterExcelDatas: Function:处理从excel读取的数据
    • filtersMappingFields: Function:声明哪些字段不允许被导入

示例:

export default {
    ...
    getMdImportConfig() {
        return {
            filterExcelDatas(dataList) {
                return dataList.filter(item => !!item.owner);
            },
            filtersMappingFields() {
                return ['field_axie__c', 'owner'];
            }
        }
    }
    ...
}

# registerListener

用法:

该方法发生在表单渲染之后,开发者可以用来注册表单事件。

注册事件:

  • addFormClickListeners
  • addFieldValueChangeListeners
  • addMdFieldValueChangeListeners
  • addMdClickListeners

示例:

  1. 监听表单按钮点击
export default {
    ...
    registerListener() {
        this.addFormClickListeners('submitAndCreate');
        this.addFormClickListeners('form_button_2');
    }
    ...
}

说明:可以监听自定义按钮,也可以监听预设按钮。参数格式为 按钮action

  1. 监听主对象值变更
export default {
    ...
    registerListener() {
        this.addFieldValueChangeListeners('name');
        this.addFieldValueChangeListeners('field_dax23__c');
    }
    ...
}

说明:参数格式为 字段apiName

  1. 监听从对像值变更
export default {
    ...
    registerListener() {
        this.addMdFieldValueChangeListeners('object_n8q24__c.field_1z0oZ__c');
		this.addMdFieldValueChangeListeners('object_n8q24__c.default__c.field_1z0oZ__c');
    }
    ...
}

说明:参数格式为 从对象apiName.业务类型.字段apiName从对象apiName.字段apiName

  1. 监听从对象按钮点击
export default {
    ...
    registerListener() {
        // 自定义按钮
        this.addMdClickListeners('object_dQ8rr__c.addMdData');
		this.addMdClickListeners('object_dQ8rr__c.delMdData');
		this.addMdClickListeners('object_dQ8rr__c.updateMdData');

        // 添加一行
		this.addMdClickListeners('object_dQ8rr__c.singleAdd');

        // 删除
		this.addMdClickListeners('object_dQ8rr__c.delRow');
    }
    ...
}

说明:可以监听自定义按钮,也可以监听预设按钮;参数格式为 从对象apiName.业务类型.按钮action从对象apiName.按钮action

# click

用法:

该方法发生在按钮点击时,用来处理点击事件。

参数:

  1. 绑定表单按钮点击事件
  • context: Object:字段的上下文环境
  • e: Object:事件对象
    • eventTarget: String:按钮apiName
    • objectApiName: String:对象apiName
    • eventName: String:固定值 - click
    • type: String:固定值 - form
  1. 绑定从对象表单点击事件
  • context: Object:字段的上下文环境
  • e: Object:事件对象
    • eventTarget: String:按钮apiName
    • objectApiName: String:对象apiName
    • eventName: String:固定值 - click
    • type: String:固定值 - md
  • next: Function: singleAdd、delRow按钮会传入此方法。执行后,会继续原有的业务操作。

# change

用法:

该方法发生在字段值变化时,用来处理值变更事件。

参数:

  1. 绑定主对象字段值变更事件
  • context: Object:字段的上下文环境
  • e: Object:事件对象
    • objectApiName: String:对象apiName
    • fieldApiName: String:字段apiName
    • eventName: String:固定值 - change
    • type: String:固定值 - data
    • objectType: String:固定值 - master
    • value: String:字段变更后的值
    • oldValue: String:字段变更前的值
  1. 绑定从对象字段值变更事件
  • context: Object:字段的上下文环境
  • e: Object:事件对象
    • objectApiName: String:从对象apiName
    • recordType: String:从对象业务类型
    • fieldApiName: String:字段apiName
    • eventName: String:固定值 - change
    • type: String:固定值 - data
    • objectType: String:固定值 - detail
    • value: String:字段变更后的值

# context

# getDescribe()

用法:

该方法返回当前对象的对象描述信息。

返回:

  • describe: Object:对象的描述信息
    • api_name: String:对象的apiName
    • display_name: String:对象的名称
    • fields: Object:对象的所有字段

示例:

const describe = context.getDescribe();
console.log(describe.api_name);
console.log(describe.fields);

# getFields()

用法:

返回该对象下的所有字段。

示例:

const fields = context.getFields();
console.log(fields.name);
console.log(fields.owner);

# getDetailData()

用法:

该方法返回从对象的对象描述信息。

参数:

  • detailObjectApiName: String:从对象的apiName

示例:

const describe = context.getDetailData('object_dQ8rr__c');
console.log(describe.api_name);
console.log(describe.fields);

# getAllDetailDescribes()

用法:

该方法返回所有从对象的对象描述信息。

示例:

const describes = context.getAllDetailDescribes();
describes.forEach(describe => {
    console.log(describe);
})

# getData()

用法:

该方法返回主对象的数据。

参数:

  • fieldApiName: String:字段的apiName(可选)

示例:

const data = context.getData();
console.log(data.name);
console.log(data.owner);

const nameValue = context.getData('name');
console.log(nameValue);

# setData()

用法:

设置数据。

参数:

  • fieldApiName: String | Object:字段的apiName
  • value: *:字段的值

示例:

context.setData('name', 'fxiaoke');
context.setData({
    'name': 'fxiaoke',
    'owner': [1000]
});

# getDetailData()

用法:

获取某个从对象某个业务类型的数据

参数:

  • apiName: String:对象的apiName
  • recordType: String:对象的业务类型(可选)

返回:

固定apiName(固定业务类型)下的从对象数据

示例:

let data = context.getDetailData('object_ad3xs__c');
let data1 = context.getDetailData('object_ad3xs__c', 'default__c');

# getAllDetailDatas()

用法:

获取所有从对象的数据。

返回:

获取所有从对象数据。

示例:

const data = context.getAllDetailDatas();
console.log(data);

# addDetailData()

用法:

新增从对象数据。支持給多个对象的多个业务类型同时添加数据。

示例:

context.addDetailData('object_R9tuj__c', 'default__c', [{
    name: 'hello fxiaoke',
}])

context.addDetailData('object_R9tuj__c', [{
    record_type: 'default__c',
    name: 'hello fxiaoke',
}])

context.addDetailData([{
    record_type: 'default__c',
    name: 'hello fxiaoke',
    object_describe_api_name: 'object_R9tuj__c'
}])

# updateDetailData()

用法:

更新从对象数据。支持給多个对象的多个业务类型同时更新数据。

示例:

context.updateDetailData('object_R9tuj__c', 'default__c', [{
    name: 'hello fxiaoke',
    rowId: '' //必传
}])

context.updateDetailData('object_R9tuj__c', [{
    record_type: 'default__c',
    name: 'hello fxiaoke',
    rowId: '' //必传
}])

context.updateDetailData([{
    record_type: 'default__c',
    name: 'hello fxiaoke',
    object_describe_api_name: 'object_R9tuj__c',
    rowId: '' //必传
}])

# deleteDetailData()

用法:

删除从对象数据。支持給多个对象的多个业务类型同时删除数据。

示例:


context.deleteDetailData('object_R9tuj__c', 'default__c', [{
    name: 'hello fxiaoke',
    rowId: '' //必传
}])

context.deleteDetailData('object_R9tuj__c', [{
    record_type: 'default__c',
    name: 'hello fxiaoke',
    rowId: '' //必传
}])

context.deleteDetailData([{
    record_type: 'default__c',
    name: 'hello fxiaoke',
    object_describe_api_name: 'object_R9tuj__c',
    rowId: '' //必传
}])

# setDetailRowStyle()

用法:

设置从对象行样式。

示例:

constext.setDetailRowStyle('object_dQ8rr__c','default__c','1669894692997240', 'font-size: 20px;')

constext.setDetailRowStyle('object_dQ8rr__c','default__c',['1669894692997240','1669894692997241'], 'background-color: red;')

constext.setDetailRowStyle([{
    record_type: 'default__c',
    object_describe_api_name: 'object_R9tuj__c',
    rowId: '1669894692997240'
}], 'background-color: red;')

# 常见示例

# 自定义字段

需求:

目前,百分比字段是以 数字+百分号 的样式呈现在用户界面上,为了提升该字段的体验,需要以进度条的交互形式来展示。

分析:

  1. 如何扩展字段组件
  2. 表单设置字段值时,如何传递给自定义的字段组件
  3. 字段组件状态变更后,字段值如何传递给表单

代码:

let vm = null;

// 自定义字段具体实现
const Progress = Vue.extend({
	props: {
		value: String
	},
	data() {
        return {
            percentage: this.value ? this.value * 1 : 0,
            colors: [
                {color: '#f56c6c', percentage: 20},
                {color: '#e6a23c', percentage: 40},
                {color: '#5cb87a', percentage: 60},
                {color: '#1989fa', percentage: 80},
                {color: '#6f7ad3', percentage: 100}
            ]
        };
    },
    methods: {
        setValue(val) {
            this.percentage = val;
        },
		//增加进度
        increase() {
            this.percentage += 10;
            if (this.percentage > 100) {
              	this.percentage = 100;
            }
			this.$emit('change', `${this.percentage}`);
        },
		//降低进度
        decrease() {
            this.percentage -= 10;
            if (this.percentage < 0) {
              	this.percentage = 0;
            }
            this.$emit('change', `${this.percentage}`);
        }
    },
	render(h) {
		return (
			<div>
				<fx-progress type="dashboard" percentage={this.percentage} color={this.colors}></fx-progress>
                <div>
                    <fx-button-group>
                        <fx-button icon="el-icon-minus" on-click={this.decrease}></fx-button>
                        <fx-button icon="el-icon-plus" on-click={this.increase}></fx-button>
                    </fx-button-group>
                </div>
			</div>
		)
	}
});


// 导出插件
export default {
    
    entry(context, field) {
		return field.type === 'percentile';
	},

    render(context, field, value) {
        if (field.type === 'percentile') {
            if (!vm) {
                vm = new Progress({
                    propsData: {
                        value // 初始值传递给自定义字段组件
                    }
                }).$mount();
                vm.$on('change', (val) => {
                    context.setData(field.api_name, val) // 自定义字段组件值变更后,通知表单修改数据模型
                });
                return vm.$el;
            }else {
                vm.setValue(value); // 表单数据模型值变更后,通知自定义字段修改值
            }
		}
    },

    beforeDestroy() {
        if (vm) {
            vm.$destroy();
            vm = null;
        }
    }
}

# 处理从对象按钮

需求:

删除从对象需要满足某些条件才允许删除;新增从对象单条数据操作按钮,点击后可以自动更新当前数据。

分析:

  1. 如何拦截从对象删除
  2. 如何新增数据操作按钮以及如何注册该按钮的点击事件

代码:

export default {

    // 定义从对象object_dQ8rr__c的单条操作按钮
    getMdOperateButtons(context, detailObjectApiName) {
		return detailObjectApiName === 'object_dQ8rr__c' ? [function() {
        	return {
        		add: [{
        			label: '自定义操作-自动更新数据',
        			action: 'single_data_btn',
					callBack(data) {
						// todo what you want
                        data.name = 'test';
                        context.updateDetailData(data);
					}
        		}]
        	}
        }] : []
	},

    // 注册点击事件
    registerListener() {
        this.addMdClickListeners('object_dQ8rr__c.delRow'); // 注册删除按钮点击事件
    },

    // 处理点击事件
    click(context, e, next) {
        if (e.type === 'md') {
            if (e.objectApiName === 'object_dQ8rr__c') {
                if (e.eventTarget === 'delRow') {
                    // 执行拦截逻辑
                    setTimeout(() => {
                        next();
                    }, 3000)
                }
            }
        }
    }
}

# 表单提醒

需求:

如果从对象的值不符合要求(主属性包含test),则修改从对象的背景色为红色,突出显示。

分析:

  1. 如何监听从对象的值变更
  2. 如何修改从对象的背景色

代码:

export default {
    registerListener() {
        this.addMdFieldValueChangeListeners('object_n8q24__c.name'); // 注册字段值变更事件
    },

    change(context, e) {
        if(e.type === 'data') {
            if (e.objectType === 'detail') {
                const data = e.data;

                if (e.value.indexOf('error') > -1) {
                    context.setDetailRowStyle(data.object_describe_api_name, data.record_type, [data.rowId], 'background-color: #ea7569!important;')
                }else {
                    context.setDetailRowStyle(data.object_describe_api_name, data.record_type, [data.rowId], '');
                }
            }
        }
    }
}
lastUpdate: 2023-2-24 16:28:31