简体中文
md.render.before
约 2090 字大约 7 分钟
2025-12-15
该钩子在从对象表格渲染之前调用,表单从对象表格渲染前执行额外的动作,包含且不限于以下功能:
扩展从表单按钮
自定义从表字段
修改从表数据
给从表添加自定义区域
参数
| 参数 | 说明 | 类型 |
|---|---|---|
| 通用参数 | 详见 | -- |
| objApiName | 从对象apiName | String |
| recordType | 从对象业务类型 | String |
返回结果
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| buttons | 从对象表格右上角通用按钮(示例)。预置按钮 | Object | -- |
| operateBtns | 从对象表格单行数据操作按钮(示例)。预置按钮 | Array | -- |
| batchButtons | 从对象表格左上角批量按钮,勾选数据之后出现(示例)。预置按钮 | Object | -- |
| columnRenders | 自定义列的渲染(示例) | Array | -- |
| columnWidthConfig | 自定义列的宽度(示例) | Object | -- |
| hideFields | 隐藏指定字段(示例) | Object | -- |
| filterBatchEditFields | 禁用指定字段的批量编辑(示例) | Array | -- |
| fakeFields | 表格里添加虚拟字段 | Array | |
| headerSlot | 从对象头部区域自定义 | Array | -- |
| footerSlot | 从对象底部区域自定义 | Array | -- |
| tableFooterSlot | 从对象表格底部区域自定义 | Object | -- |
| tableLeftSlot | 从对象左边区域自定义(示例) | Array | -- |
| titSlot | 从对象操作区域自定义(示例) | Object | -- |
| resetFields | 重置字段属性/只读/必填/label/options/type(示例) | Object | -- |
| datasErrorCallBack | 数据错误回调函数,当点提交按钮时,如果从对象有错误数据,此函数会被调用 | Function | -- |
| parseData | 提交之前处理从对象数据(示例) | Function | -- |
buttons/operateBtns/batchBtns
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| add | 添加自定义按钮 | Array | -- |
| del | 删除指定按钮 | Array | -- |
| reset | 重置按钮名称和行为 | Array | -- |
| retain | 仅保留指定按钮 | Array | -- |
resetFields
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| is_readonly | 是否只读 | Boolean | -- |
| is_required | 是否必填 | Boolean | -- |
| type | 类型 | String | -- |
| label | 标签名称 | String | -- |
| options | 选项(仅单选字段、多选字段支持) | Array | -- |
基础示例
自定义表格右上角按钮
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
if(context.objApiName === 'object_y6JkA__c') {//给指定的从表添加一个自定义按钮
return Promise.resolve({
buttons: {
add: [{
action: '',//可不传
label: '添加一些数据',
callBack(arg1, arg2) {
let {objApiName, recordType} = arg2;
let newContext = plugin.api.pluginServiceFactory({objApiName, recordType});
let datas = [{
objApiName,
recordType,
name: 'test',
//如果是查找关联,需传两个值
//field_xmewI__c对应数据的id
//field_xmewI__c__r一般对应数据的主属性
field_xmewI__c: '数据的id',
field_xmewI__c__r: '测试回填查找关联'
}]
let newDatas = newContext.dataUpdater.add(datas);
let newDataIndexs = [];
newDatas.forEach(data => newDataIndexs.push(data.rowId));
//最佳实践,添加完数据后执行计算和UI事件,此时触发的事件为新增明细事件
newContext.triggerCalAndUIEvent({newDataIndexs}).then(rst => {
if(rst.statusCode) {//计算出现问题,说明当前添加的数据有问题
newContext.end(true);//true的作用告诉从表不添加刚才的数据
} else {//没有错误时正常添加数据
newContext.end();
}
})
}
}, {
label: '批量修改数据',
callBack(arg1, arg2) {
let {objApiName, recordType} = arg2;
let newContext = plugin.api.pluginServiceFactory({objApiName, recordType});
//newContext.dataUpdater.updateData(objApiName, rowId, {})
//newContext.end()
}
}],
//删除指定的按钮
// 如果是【从某对象新建】按钮,则传入字段的apiName
//product_id就是查找关联字段的api_name
del: ['Single_Add', 'product_id']
}
})
} else if(context.objApiName === 'object_c1YBm__c') {//给指定的从表的某个业务类型增加一个按钮
return Promise.resolve({
buttons: {
default__c: {
add: [{
action: '',//可不传
label: '添加一些数据',
callBack(arg1, arg2) {
//参考上面的逻辑
}
}]
}
}
})
} else if(context.objApiName = 'object_c1YYd__c') {
return Promise.resolve({
buttons: {
retain: []//把指定从表的按钮全删除
}
})
}
}
}自定义表格单条数据操作按钮
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
//给指定的从表增加单条数据操作按钮
if(context.objApiName === 'object_y6JkA__c') {
return Promise.resolve({
operateBtns: [(trData) => {
//trData当前行数据,可以根据数据的某些不变的属性返回不同按钮
//建议用不变的属性是因为后期如果行数据变化,这里的按钮不会跟随变化
//比如这个判断,当主属性等于北京返回按钮
//但是主属性字段是可以被修改的,修改后,这个按钮依然会显示,即使已经不满足条件
//if(trData.name === '北京') {
//return {add: [....]}
//}
if(trData.record_type === 'default__c') {
return {
add: [{
action: '',//可不传
label: 'Button test',
callBack(arg1, arg2) {
let {objApiName, recordType} = arg2;
let newContext = plugin.api.pluginServiceFactory({objApiName, recordType});
newContext.dataUpdater.updateData(objApiName, arg1.rowId, {name: 'xxxxx'});
//最佳实践,添加完数据后执行计算和UI事件,此时触发的事件为字段编辑事件
newContext.triggerCalAndUIEvent({dataIndex: arg1.rowId}).then(rst => {
if(rst.statusCode) {//计算出现问题,说明当前数据有问题
newContext.end(true);//true的作用告诉不用更新数据
} else {//没有错误时正常更新数据
newContext.end();
}
})
}
}],
//隐藏删除 复制 平铺 插入
//del: ['delRowHandle', 'copyRowHandle', 'tileHandle', 'insertHandle']
//隐藏所有按钮
//retain: []
}
}
}]
})
}
}
}自定义表格批量操作按钮
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
if(context.objApiName === 'object_y6JkA__c')
return Promise.resolve({
batchButtons: {
//仅保留批量删除按钮,其它按钮隐藏
// retain: ['delSelectedHandle'],
//删除所有批量按钮,一个都不保留
// retain: [],
//添加自定义按钮
add: [{
label: '已选数据金额合计',
callBack(arg1, arg2) {
let {objApiName, recordType} = arg2;
let newContext = plugin.api.pluginServiceFactory({objApiName, recordType});
//得到当下选中的数据
let checkedDatas = newContext.dataGetter.getCheckedDatas(objApiName, recordType);
let total = 0;
checkedDatas.forEach(data => {total += (data.field_dg9xI__c || 0) * 1})
alert(`当前已选数据金额总计${total}元`)
}
}]
}
})
}
}从对象左边区域自定义
import Comp from './comp.vue'
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
if(context.objApiName === 'object_y6JkA__c') {
return Promise.resolve({
tableLeftSlot: [(el, arg2) => {
let {objApiName, recordType} = arg2;
let vm = new Vue({
render: h => h(Comp, {
on: {
change() {
let newContext = plugin.api.pluginServiceFactory();
newContext.dataUpdater.updateMaster({field_mNzUn__c: '100'});
newContext.triggerCalAndUIEvent({changeFields: ['field_mNzUn__c']})
.then(rst => {
newContext.end(!!rst.StatusCode);
})
}
}
})
}).$mount()
$(el).append(vm.$el);
return {
destroy() {
vm.$destroy();
}
}
}]
})
}
}
}自定义列宽
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
return {
columnWidthConfig: {
name: 200,
field_v1A0B__c: 300
}
}
}
}自定义列的渲染
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
// 演示自定义列的两种方式
return {
columnRenders: [{
name(cellValue, trData) {
return `<span style="color:red">${cellValue}</span>`;
}
}, {
field_dg9xI__c: {
render(cellValue, trData) {
return '<div data-action="doSome">' + cellValue + trData.name + trData.price + '</div>';
},
actionCallBacks: {
doSome(arg1) {
let {$event, $target, column, data, next} = arg1;
//let newContext = plugin.api.pluginServiceFactory();
// newContext.dataGetter.getMaster();
//修改字段的值
next({name: 'test', field_dg9xI__c: '5555'})
}
}
}
}]
}
}
}重新设置字段的只读/必填/名称等属性
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
return {
resetFields: {
name: {
is_readonly: true | false, //只读
is_required: true | false, //必填
//可以把文本字段设置为单选,一般用不到这个属性
type: 'select_one',
label: 'xxxx',
//单选多选 选项设置
options: [{
label: '选项1',
value: 'option1'
}]
}
}
}
}
}设置不支持批量编辑的字段
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
return {
filterBatchEditFields: ['name', 'price'] //name|price字段不支持批量编辑
}
}
}隐藏指定字段
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
return {
hideFields: {common:['name', 'price']}
//hideFields: {default__c:['name', 'price']} 指定业务类型隐藏
}
}
}提交之前处理从对象数据
export default class Plugin {
apply() {
return [{
event: 'md.render.before',
functional: this.mdRenderBefore.bind(this)
}]
}
mdRenderBefore(context, plugin) {
return {
parseData: [(dataList) => {
return dataList
}]
}
}
}注意事项
1. 该钩子会发生在每个从对象表格渲染之前
每个从对象的各个业务类型会渲染一个表格,每个表格渲染前都会执行此钩子。开发人员可以通过上下文的参数 objApiName 和 recordType 来区分钩子属于哪个从对象下的哪个业务类型的表格。
2. retain的优先级高于add
自定义按钮时,如果传了retain属性,add属性中的按钮将不会被创建。
附录
预置按钮
表格按钮
| 按钮 | action |
|---|---|
| 添加一行 | Single_Add |
| 从本地excel导入 | Import_Excel |
单行数据操作按钮
| 按钮 | action |
|---|---|
| 删除 | delRowHandle |
| 复制 | copyRowHandle |
| 平铺 | tileHandle |
| 插入 | insertHandle |
| 拖动 | dragHandle |
批量按钮
| 按钮 | action |
|---|---|
| 批量编辑 | tableBatchEditHandle |
| 删除 | delSelectedHandle |
| 复制 | copySelectedHandle |
常见问题
Q: 为什么plugin.api.pluginServiceFactory报错,找不到这个方法
A: 因为是在vcrm项目里写的中台插件,需要交互参数位置。mdRenderBefore(context,plugin)-->mdRenderBefore(plugin, context)
Q: 为什么按钮的callBack需要生成newContext
A: 因为当按钮执行时,之前的上下文已经被销毁,需要重写生成一个。
