如何在BPMN属性面板添加bpmn:Resource至bpmn:Definitions并扩展?
当然可以实现这个需求!你现在遇到的核心问题是之前的代码把bpmn:Resource加到了元素的extensionElements里,而我们需要把它直接挂载到bpmn:Definitions根节点下(和bpmn:Process同级),同时还要支持自定义参数扩展。下面我一步步给你拆解解决方案:
第一步:修正你的Moddle定义语法
先提个小细节,你提供的MyModdle.json里有个语法错误:MyParameter的第一个属性后少了逗号,这会导致Moddle加载失败。修正后的定义如下:
{ "name": "Resource", "extends": [ "bpmn:Resource" ], "properties": [ { "name": "parameters", "isMany": true, "type": "MyParameter" } ] }, { "name": "MyParameter", "properties": [ { "name": "myParameterType", "isAttr": true, "type": "String" }, { "name": "myParameterName", "isAttr": true, "type": "String" }, { "name": "myParameterValue", "isAttr": true, "type": "String" } ] }
这个定义是没问题的,它正确扩展了原生bpmn:Resource,添加了多实例的自定义MyParameter属性。
第二步:调整Resource的创建逻辑(核心)
之前的代码错误地将extensionElements作为父节点,我们需要改为操作根节点bpmn:Definitions,因为bpmn:Resource是它的直接子元素。
1. 获取根Definitions元素
你可以通过遍历元素的父节点找到根,或者直接从modeler实例获取:
// 方法1:从当前元素向上遍历找到根Definitions function getDefinitions(element) { let parent = element.$parent; while (parent.$type !== 'bpmn:Definitions') { parent = parent.$parent; } return parent; } // 方法2:如果你持有modeler实例,直接获取 // const definitions = modeler.getDefinitions();
2. 替换命令逻辑,添加Resource到Definitions
放弃之前针对extensionElements的cmdHelper方法,改用bpmn-js原生的element.updateModdleProperties命令直接修改Definitions的resources列表:
// 创建自定义Resource元素 function createCustomResource(bpmnFactory) { return bpmnFactory.create('bpmn:Resource', { id: 'Resource_' + Math.random().toString(36).substr(2, 9) // 生成唯一ID }); } // 创建自定义参数 function createCustomParameter(bpmnFactory, params = {}) { return bpmnFactory.create('my:MyParameter', { myParameterType: params.type || 'string', myParameterName: params.name || 'new_param', myParameterValue: params.value || '' }); } // 添加Resource到Definitions的核心命令逻辑 function addResourceToDefinitions(definitions, resource, commandStack) { // 获取现有resources列表,没有则为空数组 const existingResources = definitions.resources || []; commandStack.execute('element.updateModdleProperties', { element: definitions, moddleElement: definitions, properties: { resources: [...existingResources, resource] } }); }
3. 重写你的newElement函数
现在可以修改你之前的newElement函数,适配新的逻辑:
var newElement = function (type, prop, factory) { return function (element, bpmnFactory, commandStack) { var commands = []; var definitions = getDefinitions(element); var resource = definitions.resources?.find(r => r.id === 'your-target-resource-id'); // 按需查找现有Resource if (!resource) { // 创建新的Resource resource = createCustomResource(bpmnFactory); // 添加到Definitions addResourceToDefinitions(definitions, resource, commandStack); } // 添加自定义参数到Resource var newParam = createCustomParameter(bpmnFactory, { myParameterName: 'id-' + Date.now() }); // 更新Resource的parameters列表 commandStack.execute('element.updateModdleProperties', { element: resource, moddleElement: resource, properties: { parameters: [...(resource.parameters || []), newParam] } }); return commands; }; };
第三步:在属性面板中添加编辑控件
要在属性面板中操作这些Resource,你需要自定义一个属性面板组,因为默认面板只针对选中的流程元素,而我们要操作的是根节点的资源。
示例:添加Resource管理组
function ResourcePropertiesProvider(propertiesPanel, translate, bpmnFactory, commandStack) { this.getGroups = function(element) { const definitions = getDefinitions(element); return [ { id: 'resource-management', label: translate('Resources'), entries: [ // 添加Resource按钮 { id: 'add-resource-btn', label: translate('Add New Resource'), onClick: () => { const newResource = createCustomResource(bpmnFactory); addResourceToDefinitions(definitions, newResource, commandStack); } }, // 遍历现有Resource,生成编辑项 ...(definitions.resources || []).map(resource => ({ id: `resource-${resource.id}`, label: translate('Resource: ') + resource.id, entries: [ // 编辑Resource名称 { id: `${resource.id}-name`, label: translate('Name'), type: 'textInput', getValue: () => resource.name || '', setValue: (value) => { commandStack.execute('element.updateModdleProperties', { element: resource, moddleElement: resource, properties: { name: value } }); } }, // 编辑自定义Parameters列表 { id: `${resource.id}-parameters`, label: translate('Custom Parameters'), type: 'list', element: resource, property: 'parameters', itemLabel: (param) => param.myParameterName, createItem: () => createCustomParameter(bpmnFactory), // 参数的编辑项 itemEntries: (param) => [ { id: `${param.id}-type`, label: translate('Type'), type: 'textInput', getValue: () => param.myParameterType, setValue: (val) => updateParamProperty(param, 'myParameterType', val) }, { id: `${param.id}-name`, label: translate('Name'), type: 'textInput', getValue: () => param.myParameterName, setValue: (val) => updateParamProperty(param, 'myParameterName', val) }, { id: `${param.id}-value`, label: translate('Value'), type: 'textInput', getValue: () => param.myParameterValue, setValue: (val) => updateParamProperty(param, 'myParameterValue', val) } ] } ] })) ] } ]; }; // 辅助函数:更新参数属性 function updateParamProperty(param, propName, value) { commandStack.execute('element.updateModdleProperties', { element: param, moddleElement: param, properties: { [propName]: value } }); } propertiesPanel.registerProvider(this); } // 记得注入依赖 ResourcePropertiesProvider.$inject = [ 'propertiesPanel', 'translate', 'bpmnFactory', 'commandStack' ];
第四步:测试验证
完成以上步骤后,你可以:
- 启动应用,打开属性面板,应该能看到新增的「Resources」组
- 点击添加按钮,导出BPMN XML,查看根节点
bpmn:Definitions下是否出现了bpmn:Resource元素 - 编辑自定义参数,再次导出XML,确认参数属性已正确保存
内容的提问来源于stack exchange,提问作者Fatemeh Rahimi
相关产品推荐
相关产品推荐

