From f69a1049c57784e02d41a0a7defb93d57abd8446 Mon Sep 17 00:00:00 2001 From: xjs <1294405880@qq.com> Date: Sun, 17 Apr 2022 18:01:09 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=B7=A5=E4=BD=9C=E6=B5=81=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E4=BB=A3=E7=A0=81=E7=BC=96=E5=86=99=202=E3=80=81activ?= =?UTF-8?q?iti-starter=E6=8E=92=E9=99=A4Security=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=BC=95=E8=B5=B7=E7=9A=84=E8=B7=A8=E5=9F=9F=E9=97=AE=E9=A2=98?= =?UTF-8?q?=203=E3=80=81=E5=89=8D=E7=AB=AF=E6=B7=BB=E5=8A=A0bpm=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/system/api/RemoteUserService.java | 6 + .../factory/RemoteUserFallbackFactory.java | 9 +- .../system/controller/SysUserController.java | 8 +- .../ruoyi/system/mapper/SysUserMapper.java | 28 +- .../ruoyi/system/service/ISysUserService.java | 46 +- .../service/impl/SysUserServiceImpl.java | 4 + .../resources/mapper/system/SysUserMapper.xml | 11 +- .../business/workflow/activiti/definition.js | 38 + .../workflow/activiti/historyFormdata.js | 8 + .../api/business/workflow/activiti/task.js | 31 + .../api/business/workflow/workflow/leave.js | 62 + .../workflow/activiti/definition/index.vue | 291 ++++ .../business/workflow/activiti/task/index.vue | 188 +++ .../workflow/workflow/leave/index.vue | 459 ++++++ .../workflow/workflow/leave/leaveAll.vue | 228 +++ .../workflow/leave/leaveHistoryForm.vue | 78 + ruoyi-ui/xjs-bpmnjs/.gitignore | 3 + ruoyi-ui/xjs-bpmnjs/.npmrc | 1 + ruoyi-ui/xjs-bpmnjs/Gruntfile.js | 140 ++ ruoyi-ui/xjs-bpmnjs/app/favicon.ico | Bin 0 -> 5663 bytes ruoyi-ui/xjs-bpmnjs/app/index.html | 110 ++ ruoyi-ui/xjs-bpmnjs/app/index.js | 146 ++ ruoyi-ui/xjs-bpmnjs/package.json | 48 + ruoyi-ui/xjs-bpmnjs/resources/activiti.json | 1087 ++++++++++++++ .../customControls/CustomContextPad.js | 76 + .../resources/customControls/CustomPalette.js | 54 + .../resources/customControls/index.js | 8 + .../customTranslate/customTranslate.js | 12 + .../customTranslate/translationsGerman.js | 239 ++++ ruoyi-ui/xjs-bpmnjs/resources/newDiagram.bpmn | 13 + .../properties-panel/PropertiesActivator.js | 67 + .../properties-panel/PropertiesPanel.js | 1267 +++++++++++++++++ .../resources/properties-panel/Utils.js | 252 ++++ .../cmd/CreateAndReferenceHandler.js | 101 ++ .../cmd/CreateBusinessObjectListHandler.js | 110 ++ .../cmd/MultiCommandHandler.js | 32 + .../cmd/UpdateBusinessObjectHandler.js | 131 ++ .../cmd/UpdateBusinessObjectListHandler.js | 115 ++ .../resources/properties-panel/cmd/index.js | 27 + .../factory/CheckboxEntryFactory.js | 77 + .../factory/ComboEntryFactory.js | 118 ++ .../properties-panel/factory/EntryFactory.js | 163 +++ .../factory/EntryFieldDescription.js | 49 + .../properties-panel/factory/LabelFactory.js | 38 + .../factory/LinkEntryFactory.js | 78 + .../factory/SelectEntryFactory.js | 137 ++ .../factory/TableEntryFactory.js | 338 +++++ .../factory/TextBoxEntryFactory.js | 42 + .../factory/TextInputEntryFactory.js | 85 ++ .../factory/ValidationAwareTextInput.js | 56 + .../helper/AsyncCapableHelper.js | 76 + .../properties-panel/helper/CategoryHelper.js | 31 + .../properties-panel/helper/CmdHelper.js | 77 + .../properties-panel/helper/ElementHelper.js | 23 + .../helper/EventDefinitionHelper.js | 57 + .../helper/ExtensionElementsHelper.js | 54 + .../properties-panel/helper/FormHelper.js | 97 ++ .../helper/ImplementationTypeHelper.js | 192 +++ .../helper/InputOutputHelper.js | 144 ++ .../helper/ParticipantHelper.js | 36 + .../resources/properties-panel/index.js | 8 + .../resources/properties-panel/popup.js | 103 ++ .../activiti/ActivitiPropertiesProvider.js | 542 +++++++ .../element-templates/CreateHelper.js | 251 ++++ .../CustomElementsPropertiesActivator.js | 132 ++ .../element-templates/ElementTemplates.js | 56 + .../ElementTemplatesLoader.js | 96 ++ .../activiti/element-templates/Helper.js | 239 ++++ .../activiti/element-templates/Validator.js | 303 ++++ .../cmd/ChangeElementTemplateHandler.js | 471 ++++++ .../activiti/element-templates/cmd/index.js | 46 + .../activiti/element-templates/index.js | 13 + .../element-templates/parts/ChooserProps.js | 151 ++ .../element-templates/parts/CustomProps.js | 770 ++++++++++ .../element-templates/util/validate.js | 16 + .../provider/activiti/index.js | 9 + .../parts/AsynchronousContinuationProps.js | 16 + .../activiti/parts/CallActivityProps.js | 90 ++ .../activiti/parts/CandidateStarterProps.js | 27 + .../activiti/parts/ConditionalProps.js | 185 +++ .../activiti/parts/ConnectorDetailProps.js | 57 + .../ConnectorInputOutputParameterProps.js | 16 + .../parts/ConnectorInputOutputProps.js | 18 + .../activiti/parts/ErrorEventProps.js | 40 + .../parts/ExternalTaskConfigurationProps.js | 40 + .../activiti/parts/FieldInjectionProps.js | 21 + .../provider/activiti/parts/FormProps.js | 476 +++++++ .../activiti/parts/HistoryTimeToLiveProps.js | 27 + .../parts/InputOutputParameterProps.js | 11 + .../activiti/parts/InputOutputProps.js | 15 + .../activiti/parts/JobConfigurationProps.js | 34 + .../activiti/parts/ListenerDetailProps.js | 208 +++ .../parts/ListenerFieldInjectionProps.js | 20 + .../provider/activiti/parts/ListenerProps.js | 15 + .../activiti/parts/MultiInstanceLoopProps.js | 46 + .../activiti/parts/PropertiesProps.js | 33 + .../activiti/parts/ScriptTaskProps.js | 68 + .../parts/ServiceTaskDelegateProps.js | 151 ++ .../activiti/parts/StartEventInitiator.js | 23 + .../provider/activiti/parts/TasklistProps.js | 27 + .../provider/activiti/parts/UserTaskProps.js | 55 + .../activiti/parts/VariableMappingProps.js | 397 ++++++ .../activiti/parts/VersionTagProps.js | 45 + .../parts/implementation/AsyncContinuation.js | 130 ++ .../activiti/parts/implementation/Callable.js | 625 ++++++++ .../parts/implementation/CandidateStarter.js | 63 + .../activiti/parts/implementation/Delegate.js | 83 ++ .../implementation/ErrorEventDefinition.js | 65 + .../parts/implementation/ExtensionElements.js | 235 +++ .../activiti/parts/implementation/External.js | 44 + .../implementation/ExternalTaskPriority.js | 34 + .../parts/implementation/FieldInjection.js | 310 ++++ .../parts/implementation/HistoryTimeToLive.js | 35 + .../implementation/ImplementationType.js | 173 +++ .../parts/implementation/InputOutput.js | 225 +++ .../implementation/InputOutputParameter.js | 364 +++++ .../parts/implementation/JobPriority.js | 34 + .../parts/implementation/JobRetryTimeCycle.js | 113 ++ .../activiti/parts/implementation/Listener.js | 156 ++ .../MultiInstanceLoopCharacteristics.js | 290 ++++ .../parts/implementation/Properties.js | 209 +++ .../parts/implementation/ResultVariable.js | 53 + .../activiti/parts/implementation/Script.js | 173 +++ .../activiti/parts/implementation/Tasklist.js | 37 + .../provider/bpmn/BpmnPropertiesProvider.js | 84 ++ .../properties-panel/provider/bpmn/index.js | 4 + .../provider/bpmn/parts/DocumentationProps.js | 73 + .../provider/bpmn/parts/EventProps.js | 150 ++ .../provider/bpmn/parts/ExecutableProps.js | 40 + .../provider/bpmn/parts/IdProps.js | 38 + .../provider/bpmn/parts/LinkProps.js | 57 + .../provider/bpmn/parts/NameProps.js | 63 + .../provider/bpmn/parts/ProcessProps.js | 71 + .../CompensateEventDefinition.js | 130 ++ .../ConditionalEventDefinition.js | 54 + .../ElementReferenceProperty.js | 67 + .../implementation/ErrorEventDefinition.js | 35 + .../EscalationEventDefinition.js | 58 + .../EventDefinitionReference.js | 150 ++ .../implementation/MessageEventDefinition.js | 26 + .../bpmn/parts/implementation/Name.js | 33 + .../implementation/SignalEventDefinition.js | 26 + .../implementation/TimerEventDefinition.js | 139 ++ ruoyi-ui/xjs-bpmnjs/resources/tools.js | 273 ++++ ruoyi-ui/xjs-bpmnjs/styles/app.less | 135 ++ .../src/main/java/com/xjs/XjsWorkflowApp.java | 5 +- .../controller/ActivitiHistoryController.java | 2 + .../controller/HistoryFormDataCoroller.java | 2 + .../ProcessDefinitionController.java | 16 +- .../impl/ProcessDefinitionServiceImpl.java | 13 +- .../controller/WorkflowLeaveController.java | 125 ++ .../workflow/leave/domain/WorkflowLeave.java | 169 +++ .../leave/instener/LeaveEndStateListener.java | 25 + .../leave/mapper/WorkflowLeaveMapper.java | 79 + .../leave/service/IWorkflowLeaveService.java | 73 + .../impl/WorkflowLeaveServiceImpl.java | 155 ++ .../mapper/leave/WorkflowLeaveMapper.xml | 127 ++ .../main/resources/mybatis/mybatis-config.xml | 4 +- 158 files changed, 18767 insertions(+), 54 deletions(-) create mode 100644 ruoyi-ui/src/api/business/workflow/activiti/definition.js create mode 100644 ruoyi-ui/src/api/business/workflow/activiti/historyFormdata.js create mode 100644 ruoyi-ui/src/api/business/workflow/activiti/task.js create mode 100644 ruoyi-ui/src/api/business/workflow/workflow/leave.js create mode 100644 ruoyi-ui/src/views/business/workflow/activiti/definition/index.vue create mode 100644 ruoyi-ui/src/views/business/workflow/activiti/task/index.vue create mode 100644 ruoyi-ui/src/views/business/workflow/workflow/leave/index.vue create mode 100644 ruoyi-ui/src/views/business/workflow/workflow/leave/leaveAll.vue create mode 100644 ruoyi-ui/src/views/business/workflow/workflow/leave/leaveHistoryForm.vue create mode 100644 ruoyi-ui/xjs-bpmnjs/.gitignore create mode 100644 ruoyi-ui/xjs-bpmnjs/.npmrc create mode 100644 ruoyi-ui/xjs-bpmnjs/Gruntfile.js create mode 100644 ruoyi-ui/xjs-bpmnjs/app/favicon.ico create mode 100644 ruoyi-ui/xjs-bpmnjs/app/index.html create mode 100644 ruoyi-ui/xjs-bpmnjs/app/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/package.json create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/activiti.json create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomContextPad.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomPalette.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/customControls/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/customTranslate/customTranslate.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/customTranslate/translationsGerman.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/newDiagram.bpmn create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesActivator.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesPanel.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/Utils.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateAndReferenceHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateBusinessObjectListHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/MultiCommandHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectListHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/CheckboxEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ComboEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFieldDescription.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LabelFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LinkEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/SelectEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TableEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextBoxEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextInputEntryFactory.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ValidationAwareTextInput.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/AsyncCapableHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CategoryHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CmdHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ElementHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/EventDefinitionHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ExtensionElementsHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/FormHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ImplementationTypeHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/InputOutputHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ParticipantHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/popup.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/ActivitiPropertiesProvider.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CreateHelper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CustomElementsPropertiesActivator.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplates.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplatesLoader.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Helper.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Validator.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/ChangeElementTemplateHandler.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/ChooserProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/CustomProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/util/validate.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/AsynchronousContinuationProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CallActivityProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CandidateStarterProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConditionalProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorDetailProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputParameterProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ErrorEventProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ExternalTaskConfigurationProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FieldInjectionProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FormProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/HistoryTimeToLiveProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputParameterProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/JobConfigurationProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerDetailProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerFieldInjectionProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/MultiInstanceLoopProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/PropertiesProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ScriptTaskProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ServiceTaskDelegateProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/StartEventInitiator.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/TasklistProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/UserTaskProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VariableMappingProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VersionTagProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/AsyncContinuation.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Callable.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/CandidateStarter.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Delegate.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ErrorEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExtensionElements.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/External.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExternalTaskPriority.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/FieldInjection.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/HistoryTimeToLive.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ImplementationType.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutput.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutputParameter.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobPriority.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobRetryTimeCycle.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Listener.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/MultiInstanceLoopCharacteristics.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Properties.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ResultVariable.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Script.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Tasklist.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/BpmnPropertiesProvider.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/index.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/DocumentationProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/EventProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ExecutableProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/IdProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/LinkProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/NameProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ProcessProps.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/CompensateEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ConditionalEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ElementReferenceProperty.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ErrorEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EscalationEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EventDefinitionReference.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/MessageEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/Name.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/SignalEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/TimerEventDefinition.js create mode 100644 ruoyi-ui/xjs-bpmnjs/resources/tools.js create mode 100644 ruoyi-ui/xjs-bpmnjs/styles/app.less create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/controller/WorkflowLeaveController.java create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/domain/WorkflowLeave.java create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/instener/LeaveEndStateListener.java create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/mapper/WorkflowLeaveMapper.java create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/IWorkflowLeaveService.java create mode 100644 xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/impl/WorkflowLeaveServiceImpl.java create mode 100644 xjs-business/xjs-business-workflow/src/main/resources/mapper/leave/WorkflowLeaveMapper.xml diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java index 4620353b..67fa4939 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java @@ -9,6 +9,8 @@ import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.factory.RemoteUserFallbackFactory; import com.ruoyi.system.api.model.LoginUser; +import java.util.List; + /** * 用户服务 * 新增修改用户remote @@ -47,4 +49,8 @@ public interface RemoteUserService @PutMapping("/user/updateForRPC/{id}") R updateForRPC(@PathVariable("id") String id,@RequestBody Integer count,@RequestHeader(SecurityConstants.FROM_SOURCE) String source); + @GetMapping("/user/selectUserNameByPostCodeAndDeptId") + R> selectUserNameByPostCodeAndDeptId(@RequestParam("postCode") String postCode, + @RequestParam("deptId") Long deptId); + } diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java index d40c2133..595ae22c 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java @@ -9,9 +9,11 @@ import com.ruoyi.system.api.RemoteUserService; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; +import java.util.List; + /** * 用户服务降级处理 - * + * * @author ruoyi */ @Component @@ -41,6 +43,11 @@ public class RemoteUserFallbackFactory implements FallbackFactory updateForRPC(String id, Integer count, String source) { return R.fail("修改用户登录次数失败:" + throwable.getMessage()); } + + @Override + public R> selectUserNameByPostCodeAndDeptId(String postCode, Long deptId) { + return R.fail("selectUserNameByPostCodeAndDeptId失败:" + throwable.getMessage()); + } }; } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java index 5613fdfa..77b1da38 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java @@ -53,6 +53,12 @@ public class SysUserController extends BaseController @Autowired private ISysConfigService configService; + @GetMapping("/selectUserNameByPostCodeAndDeptId") + public R> selectUserNameByPostCodeAndDeptId(@RequestParam("postCode") String postCode, + @RequestParam("deptId") Long deptId) { + return R.ok(userService.selectUserNameByPostCodeAndDeptId(postCode,deptId)); + } + /** * 获取用户列表 */ @@ -153,7 +159,7 @@ public class SysUserController extends BaseController /** * 获取用户信息 - * + * * @return 用户信息 */ @GetMapping("getInfo") diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java index 08311e2f..3f81bd2a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -7,14 +7,14 @@ import java.util.List; /** * 用户表 数据层 - * + * * @author ruoyi */ public interface SysUserMapper { /** * 根据条件分页查询用户列表 - * + * * @param sysUser 用户信息 * @return 用户信息集合信息 */ @@ -22,7 +22,7 @@ public interface SysUserMapper /** * 根据条件分页查询未已配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -30,7 +30,7 @@ public interface SysUserMapper /** * 根据条件分页查询未分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -38,7 +38,7 @@ public interface SysUserMapper /** * 通过用户名查询用户 - * + * * @param userName 用户名 * @return 用户对象信息 */ @@ -46,7 +46,7 @@ public interface SysUserMapper /** * 通过用户ID查询用户 - * + * * @param userId 用户ID * @return 用户对象信息 */ @@ -54,7 +54,7 @@ public interface SysUserMapper /** * 新增用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -62,7 +62,7 @@ public interface SysUserMapper /** * 修改用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -70,7 +70,7 @@ public interface SysUserMapper /** * 修改用户头像 - * + * * @param userName 用户名 * @param avatar 头像地址 * @return 结果 @@ -79,7 +79,7 @@ public interface SysUserMapper /** * 重置用户密码 - * + * * @param userName 用户名 * @param password 密码 * @return 结果 @@ -88,7 +88,7 @@ public interface SysUserMapper /** * 通过用户ID删除用户 - * + * * @param userId 用户ID * @return 结果 */ @@ -96,7 +96,7 @@ public interface SysUserMapper /** * 批量删除用户信息 - * + * * @param userIds 需要删除的用户ID * @return 结果 */ @@ -104,7 +104,7 @@ public interface SysUserMapper /** * 校验用户名称是否唯一 - * + * * @param userName 用户名称 * @return 结果 */ @@ -133,4 +133,6 @@ public interface SysUserMapper * @return int */ int updateUserLoginCount(@Param("id")String id, @Param("count")Integer count); + + ListselectUserNameByPostCodeAndDeptId(String postCode,Long deptId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index e2631b9e..e7c7460e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -13,7 +13,7 @@ public interface ISysUserService { /** * 根据条件分页查询用户列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -21,7 +21,7 @@ public interface ISysUserService /** * 根据条件分页查询已分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -29,7 +29,7 @@ public interface ISysUserService /** * 根据条件分页查询未分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -37,7 +37,7 @@ public interface ISysUserService /** * 通过用户名查询用户 - * + * * @param userName 用户名 * @return 用户对象信息 */ @@ -45,7 +45,7 @@ public interface ISysUserService /** * 通过用户ID查询用户 - * + * * @param userId 用户ID * @return 用户对象信息 */ @@ -53,7 +53,7 @@ public interface ISysUserService /** * 根据用户ID查询用户所属角色组 - * + * * @param userName 用户名 * @return 结果 */ @@ -61,7 +61,7 @@ public interface ISysUserService /** * 根据用户ID查询用户所属岗位组 - * + * * @param userName 用户名 * @return 结果 */ @@ -69,7 +69,7 @@ public interface ISysUserService /** * 校验用户名称是否唯一 - * + * * @param userName 用户名称 * @return 结果 */ @@ -93,21 +93,21 @@ public interface ISysUserService /** * 校验用户是否允许操作 - * + * * @param user 用户信息 */ public void checkUserAllowed(SysUser user); /** * 校验用户是否有数据权限 - * + * * @param userId 用户id */ public void checkUserDataScope(Long userId); /** * 新增用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -115,7 +115,7 @@ public interface ISysUserService /** * 注册用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -123,7 +123,7 @@ public interface ISysUserService /** * 修改用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -131,7 +131,7 @@ public interface ISysUserService /** * 用户授权角色 - * + * * @param userId 用户ID * @param roleIds 角色组 */ @@ -139,7 +139,7 @@ public interface ISysUserService /** * 修改用户状态 - * + * * @param user 用户信息 * @return 结果 */ @@ -147,7 +147,7 @@ public interface ISysUserService /** * 修改用户基本信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -155,7 +155,7 @@ public interface ISysUserService /** * 修改用户头像 - * + * * @param userName 用户名 * @param avatar 头像地址 * @return 结果 @@ -164,7 +164,7 @@ public interface ISysUserService /** * 重置用户密码 - * + * * @param user 用户信息 * @return 结果 */ @@ -172,7 +172,7 @@ public interface ISysUserService /** * 重置用户密码 - * + * * @param userName 用户名 * @param password 密码 * @return 结果 @@ -181,7 +181,7 @@ public interface ISysUserService /** * 通过用户ID删除用户 - * + * * @param userId 用户ID * @return 结果 */ @@ -189,7 +189,7 @@ public interface ISysUserService /** * 批量删除用户信息 - * + * * @param userIds 需要删除的用户ID * @return 结果 */ @@ -197,7 +197,7 @@ public interface ISysUserService /** * 导入用户数据 - * + * * @param userList 用户数据列表 * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 * @param operName 操作用户 @@ -212,4 +212,6 @@ public interface ISysUserService * @return int */ int updateUserLoginCount(String id, Integer count); + + ListselectUserNameByPostCodeAndDeptId(String postCode,Long deptId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 4d8e8fa1..eed4d3a4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -563,4 +563,8 @@ public class SysUserServiceImpl implements ISysUserService return userMapper.updateUserLoginCount(id,count); } + public ListselectUserNameByPostCodeAndDeptId(String postCode,Long deptId){ + return userMapper.selectUserNameByPostCodeAndDeptId(postCode,deptId); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml index 1b9f8a5c..e9fbb8e3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -209,7 +209,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update sys_user set password = #{password} where user_name = #{userName} - + update sys_user set del_flag = '2' where user_id = #{userId} @@ -227,5 +227,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update sys_user set login_count = #{count} where user_id= #{id} + + + SELECT user_name FROM sys_post p + left join sys_user_post up on p.post_id = up.post_id + left join sys_user u on up.user_id= u.user_id + where post_code=#{param1} and dept_id=#{param2} - \ No newline at end of file + + diff --git a/ruoyi-ui/src/api/business/workflow/activiti/definition.js b/ruoyi-ui/src/api/business/workflow/activiti/definition.js new file mode 100644 index 00000000..684204ee --- /dev/null +++ b/ruoyi-ui/src/api/business/workflow/activiti/definition.js @@ -0,0 +1,38 @@ +import request from '@/utils/request' + +// 查询modeler列表 +export function listDefinition(query) { + return request({ + url: '/workflow/processDefinition/list', + method: 'get', + params: query + }) +} + +// 查询请假详细 +export function getDefinitionsByInstanceId(instanceId) { + return request({ + url: '/workflow/processDefinition/getDefinitions/' + instanceId, + method: 'get' + }) +} + +// 挂起激活转换 +export function suspendOrActiveApply(data) { + return request({ + url: '/workflow/processDefinition/suspendOrActiveApply', + method: 'post', + data:data + }) +} + + +// 删除Modeler +export function delDefinition(id) { + return request({ + url: '/workflow/processDefinition/remove/' + id, + method: 'delete' + }) +} + + diff --git a/ruoyi-ui/src/api/business/workflow/activiti/historyFormdata.js b/ruoyi-ui/src/api/business/workflow/activiti/historyFormdata.js new file mode 100644 index 00000000..1d9f0151 --- /dev/null +++ b/ruoyi-ui/src/api/business/workflow/activiti/historyFormdata.js @@ -0,0 +1,8 @@ +import request from '@/utils/request' +// 查询请假详细 +export function historyFromData(instanceId) { + return request({ + url: '/workflow/historyFromData/ByInstanceId/' + instanceId, + method: 'get' + }) +} diff --git a/ruoyi-ui/src/api/business/workflow/activiti/task.js b/ruoyi-ui/src/api/business/workflow/activiti/task.js new file mode 100644 index 00000000..4a9976e8 --- /dev/null +++ b/ruoyi-ui/src/api/business/workflow/activiti/task.js @@ -0,0 +1,31 @@ +import request from '@/utils/request' + +// 查询task列表 +export function listTask(query) { + return request({ + url: '/workflow/task/list', + method: 'get', + params: query + }) +} + +// 查询表单 +export function formDataShow(taskID) { + return request({ + url: '/workflow/task/formDataShow/'+taskID, + method: 'get', + }) +} + +// 查询表单 +export function formDataSave(taskID,data) { + return request({ + url: '/workflow/task/formDataSave/'+taskID, + method: 'post', + data:data + }) +} + + + + diff --git a/ruoyi-ui/src/api/business/workflow/workflow/leave.js b/ruoyi-ui/src/api/business/workflow/workflow/leave.js new file mode 100644 index 00000000..0c2a4aed --- /dev/null +++ b/ruoyi-ui/src/api/business/workflow/workflow/leave.js @@ -0,0 +1,62 @@ +import request from '@/utils/request' + +// 查询请假列表 +export function listLeave(query) { + return request({ + url: '/workflow/workflow/leave/list', + method: 'get', + params: query + }) +} +// 查询请假列表 +export function listLeaveAll(query) { + return request({ + url: '/workflow/workflow/leave/listAll', + method: 'get', + params: query + }) +} + +// 查询请假详细 +export function getLeave(id) { + return request({ + url: '/workflow/workflow/leave/' + id, + method: 'get' + }) +} + + +// 新增请假 +export function addLeave(data) { + return request({ + url: '/workflow/workflow/leave', + method: 'post', + data: data + }) +} + +// 修改请假 +export function updateLeave(data) { + return request({ + url: '/workflow/workflow/leave', + method: 'put', + data: data + }) +} + +// 删除请假 +export function delLeave(id) { + return request({ + url: '/workflow/workflow/leave/' + id, + method: 'delete' + }) +} + +// 导出请假 +export function exportLeave(query) { + return request({ + url: '/workflow/workflow/leave/export', + method: 'get', + params: query + }) +} diff --git a/ruoyi-ui/src/views/business/workflow/activiti/definition/index.vue b/ruoyi-ui/src/views/business/workflow/activiti/definition/index.vue new file mode 100644 index 00000000..5fb3bc65 --- /dev/null +++ b/ruoyi-ui/src/views/business/workflow/activiti/definition/index.vue @@ -0,0 +1,291 @@ + + + + + + + + + + + 搜索 + 重置 + + + + + + 在线绘制流程 + + + + 部署流程 + + + + + + + + + + + + + + + + + + {{ scope.row.suspendState!=1?'挂起':'激活'}} + + + + + 查看 + + {{scope.row.suspendState==1?'挂起':'激活'}} + + + 删除 + + + + + + + + + + + + + + + + + + + + 将文件拖到此处,或 + 点击上传 + + 提示:仅允许导入“bpmn”、“bar”或“zip”格式文件! + + + + + + + + diff --git a/ruoyi-ui/src/views/business/workflow/activiti/task/index.vue b/ruoyi-ui/src/views/business/workflow/activiti/task/index.vue new file mode 100644 index 00000000..57570799 --- /dev/null +++ b/ruoyi-ui/src/views/business/workflow/activiti/task/index.vue @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + 审批 + + + + + + + + + + + + + + + {{defaults}} + + + + + + + + + + + + + + diff --git a/ruoyi-ui/src/views/business/workflow/workflow/leave/index.vue b/ruoyi-ui/src/views/business/workflow/workflow/leave/index.vue new file mode 100644 index 00000000..5cf7dc7f --- /dev/null +++ b/ruoyi-ui/src/views/business/workflow/workflow/leave/index.vue @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + 新增 + + + + 导出 + + + + + + + + + + + + + + {{ parseTime(scope.row.leaveStartTime, '{y}-{m}-{d}') }} + + + + + {{ parseTime(scope.row.leaveEndTime, '{y}-{m}-{d}') }} + + + + + + + + + {{ stateFormat(scope.row) }} + + + {{ scope.row.taskName }} + + + + + + + 修改 + + + + + + + + + + 审批详情 + + + 查看进度 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveAll.vue b/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveAll.vue new file mode 100644 index 00000000..1f7c45bf --- /dev/null +++ b/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveAll.vue @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + 导出 + + + + + + + + + + + + + + {{ parseTime(scope.row.leaveStartTime, '{y}-{m}-{d}') }} + + + + + {{ parseTime(scope.row.leaveEndTime, '{y}-{m}-{d}') }} + + + + + + + 审批详情 + + + + + + + + + + + + + + + + + diff --git a/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveHistoryForm.vue b/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveHistoryForm.vue new file mode 100644 index 00000000..c47214d0 --- /dev/null +++ b/ruoyi-ui/src/views/business/workflow/workflow/leave/leaveHistoryForm.vue @@ -0,0 +1,78 @@ + + + + 请假人:{{ form.createName }} + + + + + + + + + + + + + + + + + + + + {{ historyData.taskNodeName }} + 审批人:{{ historyData.createName }} + 审批时间:{{ historyData.createdDate }} + + + + + + + + + + + + diff --git a/ruoyi-ui/xjs-bpmnjs/.gitignore b/ruoyi-ui/xjs-bpmnjs/.gitignore new file mode 100644 index 00000000..dc93b121 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +tmp/ +dist/ \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/.npmrc b/ruoyi-ui/xjs-bpmnjs/.npmrc new file mode 100644 index 00000000..9cf94950 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/Gruntfile.js b/ruoyi-ui/xjs-bpmnjs/Gruntfile.js new file mode 100644 index 00000000..5da314c0 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/Gruntfile.js @@ -0,0 +1,140 @@ + var path = require('path'); + +module.exports = function(grunt) { + + require('load-grunt-tasks')(grunt); + + /** + * Resolve external project resource as file path + */ + function resolvePath(project, file) { + return path.join(path.dirname(require.resolve(project)), file); + } + + + grunt.initConfig({ + browserify: { + options: { + browserifyOptions: { + debug: true + }, + transform: [ + [ 'stringify', { + extensions: [ '.bpmn' ] + } ] + ], + plugin: [ + 'esmify' + ] + }, + watch: { + options: { + watch: true + }, + files: { + 'dist/index.js': [ 'app/**/*.js' ] + } + }, + app: { + files: { + 'dist/index.js': [ 'app/**/*.js' ] + } + } + }, + + copy: { + diagram_js: { + files: [ + { + src: resolvePath('diagram-js', 'assets/diagram-js.css'), + dest: 'dist/css/diagram-js.css' + } + ] + }, + bpmn_js: { + files: [ + { + expand: true, + cwd: resolvePath('bpmn-js', 'dist/assets'), + src: ['**/*.*', '!**/*.js'], + dest: 'dist/vendor' + } + ] + }, + app: { + files: [ + { + expand: true, + cwd: 'app/', + src: ['**/*.*', '!**/*.js'], + dest: 'dist' + } + ] + } + }, + + less: { + options: { + dumpLineNumbers: 'comments', + paths: [ + 'node_modules' + ] + }, + + styles: { + files: { + 'dist/css/app.css': 'styles/app.less' + } + } + }, + + watch: { + options: { + livereload: true + }, + + samples: { + files: [ 'app/**/*.*' ], + tasks: [ 'copy:app' ] + }, + + less: { + files: [ + 'styles/**/*.less', + 'node_modules/bpmn-js-properties-panel/styles/**/*.less' + ], + tasks: [ + 'less' + ] + }, + }, + + connect: { + livereload: { + options: { + port: 9013, + livereload: true, + hostname: 'localhost', + open: true, + base: [ + 'dist' + ] + } + } + } + }); + + // tasks + + grunt.registerTask('build', [ 'copy', 'less', 'browserify:app' ]); + + grunt.registerTask('auto-build', [ + 'copy', + 'less', + 'browserify:watch', + 'connect:livereload', + 'watch' + ]); + + grunt.registerTask('default', [ 'build' ]); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/app/favicon.ico b/ruoyi-ui/xjs-bpmnjs/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e26376026420542212ed58d90d0ed34f554fa4ae GIT binary patch literal 5663 zcmZ`*WmMD;u>DcGh#=ia^G8y;1Xgl^C8S$Amyqrd1eKPKB}75GVToN(=@g_xS|pcV zYT@y|zH{E0Gjl)8mzgE0vwe;xGTK9)Pb`Ew71o)8mn z03f3HU&jG*@@N6zk*2evqK=M}hmVK1lZPjZnxZ0$rG^oYPn^M z{S!ll*~7X_SR}y4UJ2?aHTg{X39ybPB?tGsd;iFgl8P)3V$l6|>JbF~eyxxj;rR07 zd($`rbIAkd#nPtGAoTwJ^~`n0R^HalXyDkB2r_c6l)s-{04d#fFQjLgle8h-1IP$m zD#!{x3+dmXAC3e)0C0#G7!c-DD}RGi;{o6To>KxGZMTC>A z3-k-<_frD>v_P$1gWV$_4FF()Aqs3jIWe$zswPJO%$B7t(g3rc8OuOG0uGSPt;&H5 zZU?LkB6az2yM6$Lm0&gj{H|)82$N=ERon<90pOQtocsiA1w>>k@C^ejlDL54Q;HEh z7ARif^NG%tve%yP5D*-oYbbprQ)5De5|RFk-v9V;WsP<12dqxPn&ug)1K|c+US=*k z1!M~kI{Fv@=r6~=-%83SZ~fg^{p+v=L!b71zI8qHV3T7#TE6Xw$HfOowZ_o%uQxZR z@jUx*YJEFh%glgzL%?bI(n4f`u+a3;ub|7gK*<~M)BGZx{ufM)kBEr&Icj2R4kJkKK8V$4;1OQ5fkvz38A3pw0 zS=mLB_noPuiw4*FffD#JN7oBdg$ElEjE{}_(gsxj19@f+tJdn0)p$cQj1TIk1rY^mS08##l> zFS`S5r0bH6RVuj-Sf8@yb6WmKLh(8k!a*|dX+!G~D`&E>8j+eSWC6neMemE;1gUc# zlxsKHZQ#!as6L{SB{QWZ`AM?&r|W^A8!eR5J@40`gr7Ndzoe0?i`mO>;(sj=R>&?a ze>GB;KM5*-FI`}&=2qyZBd8Z!Mj`5(!#R>mtvK|Bzj*3bjZx+( zugnS8e-F2}wxdq{9}~wANA*E$xanN!g6T?WTj&I{p(O;rGqd~kpU((0WIJX($?`BT z<~ipHp-LGfPnS+NOb<)nD%UsgHjtkREGN>hFnCg7X&73fV$h(oUPd@cT`^V0WYAtF zUOlSoubZSZ_Ud&p>NWQ5l`V07%sZ9B7)Y_cZA&j*0xNZ|u>Fy-!nBtm-Y%bOmZpta z{pB9ikKmfYPcRs&r|4boQ0b830RQ`D1c#)zZskyFE>C@wb(DBCm>-W{p1*F|rOKfy ztV&`&XdX3hv+uP}y}vt;_Vt8=;e7BjX*X$%FJYT_+pD&BZ416*J958mcLTQx&j!y( zwwK0L&)iOn&uDhg)97(#iRYpq@nkxfkfiP5aI)<`*DPnm_+j+wH?kq8wv=wC;&HX& z{}5aUv5xCv0W@+Bl^%>Xm7;&_7hPXi+c*m^eChtuvw?axlIEJ@&^F%q+h=&VpKq~p zwsK%EQEDpBHQyRF*RgPu@b0T}UXOa5cwAq`d`8F+L55}qrZUS=&M?sM%y6bsZQ6X7 zZ`W0bWI(Mk~TUBmVw_mQ?GUXa&(zA(YXL|1QLVGuRkM?r*9_&k zwk(Tc51S6l4tsc$e=T!0giX5WTn#*?KGGtv!ugJ~iGz%!k8Hqm#bd_L#{c?Ij39xa z{ej?PIVy$6gv2JyUa1~kG{+2=wjzs;d^zJ(gCIDSDZ|zCVJ_&?X|lwaG0-w;m`BMa zbbGiN^nOJZ_8!6POqWe_8A|z#N4Q*I=T)Pg&l?{M-*n}M$+aUg@hGV*zEx(yrP<5R zvC;*m3$xwJMMNOV5s?A07s^MO;hx@Ws(KdgJ>ZozUy@-}kxGkk2THy1y* z()`^X9m@BAVIpRd93uHHi#)Slelv_l&=Ly*a}I*8haSww)z(F$9qayvD9oF0w8fRKf5n_YnO;Y8?=(@=c| zR%gvv*WlPCaPc@%H)`VRS4G~pMxyCuX#+#<)u*Pdwp7;Xb_Qsd%qcU&a2}fU*Oi`? z->NTaRS@)g`5St&CmZ)ZyDU*h3tOWb+5#jbk?XNU0zQ8ia8{%VmM0JWO(hS z{>P^%$mJ|?q;X_$1W(LbY~O6SxpLvSNWAzw2p(=RWQeV*XhF?!%};kO`3IknL@`mx z{6VMfbu{q?7`Y;qL(kkN4&E*$(c3Vzb^Z-oLa6#{_v9x9e+_)R)mWRzbB=axOX+<2S1UTRmG57&~H zoy=Yg#6WMdT`gW&ARQIQ^5toK4xlZsF#{)mwvsFkJ3LR>Fg6REEgDs_)v~H#p4e4L zjhV-;J!WX%=tZ^9sphWCIQn<^l}p!@_sqqNfJH$d65YGU(BjUu#E9T*JG<~Z->30^ zbO2qn2ucd5xk1ficOG6n*$HpFt+VfPTe-06vKsqo@&rvn7@L2acK17WbwYJmb&6eu zJs}Cs%*;Sck36;;O@tch>1SA=A0-H zxmTMkwh&!S00`m)fQTpnxV*c^Z2<6n4gfn=03e+O05l$-UiYZnt5K+$(o6k-`Muo0 zcym>FU%0_pH42@7ux-1Sz5P>)l9j9n94!%D$j3VkQNvGRvkoMVn+0?ce(da&q$%L8 zpoTp4=XU9KU+tUf5sKZM9OT9dxZlrxw3GT|WkWHiVoTU7q|w9h_}k2>RB2dWOBh;=T%k+Loz^cP7s&cQHe04Sf3?2Uc{|uFi_q7&Y2h>5E;_jAH4oWN z*|)r?3&mKN5Ygr~KU_?_J@Y>L8p~TX>*3W?*;s7Ol0Gab+Fn#lovzHGgPdF6lSi)G zL^yLVH+_Q=>wUEj-%sE@TUwrf1xP~1p7_iN_cAh+sDxHG1s_+;wKCzchDeCAOo-@o}`asDR~{uPgu1&}n#Oa=LFsLvp3f`C>Vt~|jK zy_%nl{Zg&~$MZF%AA1=UPk~<8^!g4H@3cdr`6qHkzF~rSpo=V%Q{$Dr?VYlliu04v z%=&RRf@F2de7c>);typLsxv{6>P2a7CpLZDX$>arZUIc2_Ku zUlbW`031ZK?1SN6t^_0fyGvg`-+!y|wIj(a0BaG-bmnF! z-?&Ny8zS6sLm&VVOE>O+ox*~U^9i^5Cev4Mr=}OVv(#jGI%h6)ozpvIw=QeWg5yL% zxc;dSYTByPsn;~w8I3%nVM7fPj~q;T4;*eQEH((##3K+F+ELsa=X*VuO?{$UoJERCFv1zCRtLIenGy2;i*IhzdLb#!lN%sklL-`-+F z?JxllW2nPY*Y~!;oIPgyr6C68E{%9$}}MS`_bfXO`Ru~*8xi-vjX-H zvjoT^#5dq8?}IJ&Wlp}ze&Elo>fpvkve9{Y{0o(4l0UkcbJe=OGP1WBh}U=wuzoO( zCb3vXz{I}y=8r136RhGZj7?Wab`-)4x%6(E35ET$*S>Gr{7Hy?1 zPvuKMN4}VU7FTXrm>eeq5bN>rBwlp`PgxV`{`=85$()C5uFqLw0HxJzMi4{*__${J zMO_0Q;^bTGu%N6*_-eEle8n4*dr{LGd=cI^nYaDe)$!S|w^k}Q2j^)sa|wa)rOWr7 z=U@&U{>sTuswbr)?Sjc9{E5BTD&WCFGRb!kCS_jD{BTS9)Yijf$eoGejH$BRliS>kQVwr#VP zPs^4Xc>MxrsW#M9V*lD85LOCp=F8J-00UjX^#H61y@ElSuoh4Tf)joqVWmY3|`1 zzHE?to7@Gpk`sq@4s#@)7@1z!JPU>^GKJpn>%Q;Y^>4==VlYTCO|4^&7;9(e5&vsb23+jj1) z4F{o&?1`kXX!p1QbG-x^0H9^JkC(#5i6HC4TWS(z9%5Q}!C`+cIJOr-(fMiVq%-|BreT|=+0PWgXb&y5S$ zG_jI1l%yt}bT4l#k^g0eq2yHHjK&w{?`d3k@CQ?v1K)MT#dYWTTR+A7RoqtH(&|aO_;V>9LbLXPn3YBbp>+MnYOoTceweya=B)lEz5H zLp=NDAK0Im^8*inYho^qYR#Qdzn_6Db?UQTs4j<|%h}JQ5#? z5{Fs+B?@B0C()s2L3QFMo?LZZrBRzLX=X>-xfw1_^{nkMY^?6lVgoW|%aOd~y;V$f zSC2PJkfFe5A(&8sdo{0Co%f9>o#kz*CRzHQ8F$tEB>cewUnj)^>+%O%(dyCa!bQiP zd$9D}qa>x9CI;OPHw~G}AbY<}mG;j)*X33HunLBdiRVoznp0xEgd+S?KC>~mPK80W zQ^foF{<7rqIFN9hCB? zZ{1Q3@oG>#AA8vR@Mza{MS#=Uc_yV~`NUvJ{jza zT|v*pR%1$2TRUMF0e`DV+%8O#ii1Jz8+U5lkts*sd)3SKz%c(j|OkN$*b3z1o8lke_ zZzLZqleC$I#|o*|>1;QvIPMtF8WlW@z%EFY@*W$g1UVFe01tVC?CaWvKX+N~&SMFh w3o}1aSIuJtnzw?rKNs-3{y)=#g);%#4FR;juZ0`#H8`NAtff?~VD + + + + + 在线绘制流程 + + + + + + + + + + + + + 无法显示bpms2.0 + + 错误详细信息 + + + + + + + + + + + + 导入 + + + + 导出 + + + + 部署 + + + + + 部署流程 + + 确认是否部署该流程 + + + + + + 确定 + 取消 + + + + + + \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/app/index.js b/ruoyi-ui/xjs-bpmnjs/app/index.js new file mode 100644 index 00000000..31c27ef4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/app/index.js @@ -0,0 +1,146 @@ + +import $ from 'jquery'; +import BpmnModeler from 'bpmn-js/lib/Modeler'; +//import propertiesPanelModule from '../resources/properties-panel'; +import propertiesPanelModule from 'bpmn-js-properties-panel'; +import propertiesProviderModule from '../resources/properties-panel/provider/activiti'; +import activitiModdleDescriptor from '../resources/activiti.json'; +import customTranslate from '../resources/customTranslate/customTranslate'; +import customControlsModule from '../resources/customControls'; +import tools from '../resources/tools' +import diagramXML from '../resources/newDiagram.bpmn'; +const proHost = window.location.protocol + "//" + window.location.host; +const href = window.location.href.split("bpmnjs")[0]; +const key = href.split(window.location.host)[1]; +const publicurl = proHost + key; + +// 添加翻译组件 +var customTranslateModule = { + translate: ['value', customTranslate] +}; +var container = $('#js-drop-zone'); +var canvas = $('#js-canvas'); +var bpmnModeler = new BpmnModeler({ + container: canvas, + propertiesPanel: { + parent: '#js-properties-panel' + }, + additionalModules: [ + propertiesPanelModule, + propertiesProviderModule, + customControlsModule, + customTranslateModule + ], + moddleExtensions: { + activiti:activitiModdleDescriptor + } +}); +container.removeClass('with-diagram'); +// 判断浏览器支持程度 +if (!window.FileList || !window.FileReader) { + window.alert('请使用谷歌、火狐、IE10+浏览器'); +} else { + tools.registerFileDrop(container, tools.createDiagram(diagramXML, bpmnModeler, container)); +} + + +$(function () { + // 创建bpmn + var param = tools.getUrlParam(window.location.href) + $('.item').show() + if (param.type === 'addBpmn') { + tools.createDiagram(diagramXML, bpmnModeler, container); + } else if (param.type === 'lookBpmn') { //编辑bpmn + $('.item').hide() + $('.download').show() + const Id = param.deploymentFileUUID || '6d4af2dc-bab0-11ea-b584-3cf011eaafca' + const Name=param.deploymentName || 'String.bpmn' + const instanceId=param.instanceId + var param={ + "deploymentId":Id, + "resourceName":decodeURI(Name) + } + if(instanceId){ + var param1={ + instanceId + } + $.ajax({ + url: localStorage.getItem("VUE_APP_BASE_API")+'/activitiHistory/gethighLine', + // url: 'http://localhost:8080/activitiHistory/gethighLine', + type: 'GET', + data: param1, + dataType:'json', + success: function (result) { + console.log(result) + var ColorJson=tools.getByColor(result.data) + $.ajax({ + url: localStorage.getItem("VUE_APP_BASE_API")+'/processDefinition/getDefinitionXML', + // url: 'http://localhost:8080/processDefinition/getDefinitionXML', + type: 'GET', + data: param, + dataType:'text', + success: function (result) { + var newXmlData = result + tools.createDiagram(newXmlData, bpmnModeler, container); + setTimeout(function () { + for (var i in ColorJson) { + tools.setColor(ColorJson[i],bpmnModeler) + } + }, 200) + }, + error: function (err) { + console.log(err) + } + }); + }, + error: function (err) { + console.log(err) + } + }); + }else{ + //加载后台方法获取xml + $.ajax({ + url: localStorage.getItem("VUE_APP_BASE_API")+'/processDefinition/getDefinitionXML', + // url: 'http://localhost:8080/processDefinition/getDefinitionXML', + type: 'GET', + data: param, + dataType:'text', + success: function (result) { + var newXmlData = result + tools.createDiagram(newXmlData, bpmnModeler, container); + }, + error: function (err) { + console.log(err) + } + }); + } + } else if(param.type === "historyBpmn") { // bpmn历史 + $('.item').hide() + $('.download').show() + } + // 点击新增 + $('#js-download-diagram').on("click", function () { + tools.syopen('alert') + }) + + // 点击取消 + $('.cancel').on("click",function () { + tools.syhide('alert') + }) + // 点击确定 + $('#sure').on('click',function(){ + // const text=$("#deploymentName").val() + tools.saveBpmn(bpmnModeler) + }) + + + + // 点击下载 + $("#downloadBpmn").on("click", function () { + tools.downLoad(bpmnModeler) + }) + // 点击上传 + $("#uploadFile").on("change", function () { + tools.upload(bpmnModeler,container) + }) +}); diff --git a/ruoyi-ui/xjs-bpmnjs/package.json b/ruoyi-ui/xjs-bpmnjs/package.json new file mode 100644 index 00000000..5d68d6b4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/package.json @@ -0,0 +1,48 @@ +{ + "name": "bpmn-js-example-properties-panel", + "version": "0.0.0", + "description": "A bpmn-js modeler + properties panel example", + "main": "app/index.js", + "scripts": { + "all": "grunt", + "dev": "grunt auto-build" + }, + "repository": { + "type": "git", + "url": "https://github.com/bpmn-io/bpmn-js-examples" + }, + "keywords": [ + "bpmnjs-example" + ], + "author": { + "name": "Nico Rehwaldt", + "url": "https://github.com/nikku" + }, + "contributors": [ + { + "name": "bpmn.io contributors", + "url": "https://github.com/bpmn-io" + } + ], + "license": "MIT", + "devDependencies": { + "esmify": "^2.1.1", + "grunt": "^1.0.4", + "grunt-browserify": "^5.3.0", + "grunt-contrib-connect": "^2.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-less": "^2.0.0", + "grunt-contrib-watch": "^1.1.0", + "load-grunt-tasks": "^5.0.0", + "stringify": "^5.2.0" + }, + "dependencies": { + "bpmn-js": "^7.0.0", + "bpmn-js-properties-panel": "^0.32.0", + "camunda-bpmn-moddle": "^4.0.1", + "diagram-js": "^5.0.0", + "jquery": "^3.4.1", + "min-dash": "^3.5.0", + "x2js": "^3.4.0" + } +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/activiti.json b/ruoyi-ui/xjs-bpmnjs/resources/activiti.json new file mode 100644 index 00000000..c8d3ba0c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/activiti.json @@ -0,0 +1,1087 @@ +{ + "name": "Activiti", + "uri": "http://activiti.org/bpmn", + "prefix": "activiti", + "xml": { + "tagAlias": "lowerCase" + }, + "associations": [], + "types": [ + { + "name": "Definitions", + "isAbstract": true, + "extends": [ + "bpmn:Definitions" + ], + "properties": [ + { + "name": "diagramRelationId", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "InOutBinding", + "superClass": [ + "Element" + ], + "isAbstract": true, + "properties": [ + { + "name": "source", + "isAttr": true, + "type": "String" + }, + { + "name": "sourceExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "target", + "isAttr": true, + "type": "String" + }, + { + "name": "businessKey", + "isAttr": true, + "type": "String" + }, + { + "name": "local", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "variables", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "In", + "superClass": [ + "InOutBinding" + ], + "meta": { + "allowedIn": [ + "bpmn:CallActivity" + ] + } + }, + { + "name": "Out", + "superClass": [ + "InOutBinding" + ], + "meta": { + "allowedIn": [ + "bpmn:CallActivity" + ] + } + }, + { + "name": "AsyncCapable", + "isAbstract": true, + "extends": [ + "bpmn:Activity", + "bpmn:Gateway", + "bpmn:Event" + ], + "properties": [ + { + "name": "async", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "asyncBefore", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "asyncAfter", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "exclusive", + "isAttr": true, + "type": "Boolean", + "default": true + } + ] + }, + { + "name": "JobPriorized", + "isAbstract": true, + "extends": [ + "bpmn:Process", + "activiti:AsyncCapable" + ], + "properties": [ + { + "name": "jobPriority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "SignalEventDefinition", + "isAbstract": true, + "extends": [ + "bpmn:SignalEventDefinition" + ], + "properties": [ + { + "name": "async", + "isAttr": true, + "type": "Boolean", + "default": false + } + ] + }, + { + "name": "ErrorEventDefinition", + "isAbstract": true, + "extends": [ + "bpmn:ErrorEventDefinition" + ], + "properties": [ + { + "name": "errorCodeVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "errorMessageVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Error", + "isAbstract": true, + "extends": [ + "bpmn:Error" + ], + "properties": [ + { + "name": "activiti:errorMessage", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "PotentialStarter", + "superClass": [ + "Element" + ], + "properties": [ + { + "name": "resourceAssignmentExpression", + "type": "bpmn:ResourceAssignmentExpression" + } + ] + }, + { + "name": "FormSupported", + "isAbstract": true, + "extends": [ + "bpmn:StartEvent", + "bpmn:UserTask" + ], + "properties": [ + { + "name": "formHandlerClass", + "isAttr": true, + "type": "String" + }, + { + "name": "formKey", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "TemplateSupported", + "isAbstract": true, + "extends": [ + "bpmn:Process", + "bpmn:FlowElement" + ], + "properties": [ + { + "name": "modelerTemplate", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Initiator", + "isAbstract": true, + "extends": [ "bpmn:StartEvent" ], + "properties": [ + { + "name": "initiator", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ScriptTask", + "isAbstract": true, + "extends": [ + "bpmn:ScriptTask" + ], + "properties": [ + { + "name": "resultVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "resource", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Process", + "isAbstract": true, + "extends": [ + "bpmn:Process" + ], + "properties": [ + { + "name": "candidateStarterConfiguration", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateStarterUsers", + "isAttr": true, + "type": "String" + }, + { + "name": "versionTag", + "isAttr": true, + "type": "String" + }, + { + "name": "historyTimeToLive", + "isAttr": true, + "type": "String" + }, + { + "name": "isStartableInTasklist", + "isAttr": true, + "type": "Boolean", + "default": true + }, + { + "name": "process-is-executable", + "isAttr": true, + "type": "Boolean", + "default": true + } + ] + }, + { + "name": "EscalationEventDefinition", + "isAbstract": true, + "extends": [ + "bpmn:EscalationEventDefinition" + ], + "properties": [ + { + "name": "escalationCodeVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FormalExpression", + "isAbstract": true, + "extends": [ + "bpmn:FormalExpression" + ], + "properties": [ + { + "name": "resource", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Assignable", + "extends": [ "bpmn:UserTask" ], + "properties": [ + { + "name": "assignee", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateUsers", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateGroups", + "isAttr": true, + "type": "String" + }, + { + "name": "dueDate", + "isAttr": true, + "type": "String" + }, + { + "name": "followUpDate", + "isAttr": true, + "type": "String" + }, + { + "name": "priority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "CallActivity", + "extends": [ "bpmn:CallActivity" ], + "properties": [ + { + "name": "calledElementBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "calledElementVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "calledElementVersionTag", + "isAttr": true, + "type": "String" + }, + { + "name": "calledElementTenantId", + "isAttr": true, + "type": "String" + }, + { + "name": "caseRef", + "isAttr": true, + "type": "String" + }, + { + "name": "caseBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "caseVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "caseTenantId", + "isAttr": true, + "type": "String" + }, + { + "name": "variableMappingClass", + "isAttr": true, + "type": "String" + }, + { + "name": "variableMappingDelegateExpression", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ServiceTaskLike", + "extends": [ + "bpmn:ServiceTask", + "bpmn:BusinessRuleTask", + "bpmn:SendTask", + "bpmn:MessageEventDefinition" + ], + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "resultVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "DmnCapable", + "extends": [ + "bpmn:BusinessRuleTask" + ], + "properties": [ + { + "name": "decisionRef", + "isAttr": true, + "type": "String" + }, + { + "name": "decisionRefBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "decisionRefVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "mapDecisionResult", + "isAttr": true, + "type": "String", + "default": "resultList" + }, + { + "name": "decisionRefTenantId", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ExternalCapable", + "extends": [ + "activiti:ServiceTaskLike" + ], + "properties": [ + { + "name": "type", + "isAttr": true, + "type": "String" + }, + { + "name": "topic", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "TaskPriorized", + "extends": [ + "bpmn:Process", + "activiti:ExternalCapable" + ], + "properties": [ + { + "name": "taskPriority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Properties", + "superClass": [ + "Element" + ], + "meta": { + "allowedIn": [ "*" ] + }, + "properties": [ + { + "name": "values", + "type": "Property", + "isMany": true + } + ] + }, + { + "name": "Property", + "superClass": [ + "Element" + ], + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "value", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "Connector", + "superClass": [ + "Element" + ], + "meta": { + "allowedIn": [ + "activiti:ServiceTaskLike" + ] + }, + "properties": [ + { + "name": "inputOutput", + "type": "InputOutput" + }, + { + "name": "connectorId", + "type": "String" + } + ] + }, + { + "name": "InputOutput", + "superClass": [ + "Element" + ], + "meta": { + "allowedIn": [ + "bpmn:FlowNode", + "activiti:Connector" + ] + }, + "properties": [ + { + "name": "inputOutput", + "type": "InputOutput" + }, + { + "name": "connectorId", + "type": "String" + }, + { + "name": "inputParameters", + "isMany": true, + "type": "InputParameter" + }, + { + "name": "outputParameters", + "isMany": true, + "type": "OutputParameter" + } + ] + }, + { + "name": "InputOutputParameter", + "properties": [ + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + }, + { + "name": "definition", + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "InputOutputParameterDefinition", + "isAbstract": true + }, + { + "name": "List", + "superClass": [ "InputOutputParameterDefinition" ], + "properties": [ + { + "name": "items", + "isMany": true, + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "Map", + "superClass": [ "InputOutputParameterDefinition" ], + "properties": [ + { + "name": "entries", + "isMany": true, + "type": "Entry" + } + ] + }, + { + "name": "Entry", + "properties": [ + { + "name": "key", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + }, + { + "name": "definition", + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "Value", + "superClass": [ + "InputOutputParameterDefinition" + ], + "properties": [ + { + "name": "id", + "isAttr": true, + "type": "String" + }, + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "Script", + "superClass": [ "InputOutputParameterDefinition" ], + "properties": [ + { + "name": "scriptFormat", + "isAttr": true, + "type": "String" + }, + { + "name": "resource", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "Field", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "activiti:ServiceTaskLike", + "activiti:ExecutionListener", + "activiti:TaskListener" + ] + }, + "properties": [ + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "expression", + "type": "String" + }, + { + "name": "stringValue", + "isAttr": true, + "type": "String" + }, + { + "name": "string", + "type": "String" + } + ] + }, + { + "name": "InputParameter", + "superClass": [ "InputOutputParameter" ] + }, + { + "name": "OutputParameter", + "superClass": [ "InputOutputParameter" ] + }, + { + "name": "Collectable", + "isAbstract": true, + "extends": [ "bpmn:MultiInstanceLoopCharacteristics" ], + "superClass": [ "activiti:AsyncCapable" ], + "properties": [ + { + "name": "collection", + "isAttr": true, + "type": "String" + }, + { + "name": "elementVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FailedJobRetryTimeCycle", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "activiti:AsyncCapable", + "bpmn:MultiInstanceLoopCharacteristics" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "ExecutionListener", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "bpmn:Task", + "bpmn:ServiceTask", + "bpmn:UserTask", + "bpmn:BusinessRuleTask", + "bpmn:ScriptTask", + "bpmn:ReceiveTask", + "bpmn:ManualTask", + "bpmn:ExclusiveGateway", + "bpmn:SequenceFlow", + "bpmn:ParallelGateway", + "bpmn:InclusiveGateway", + "bpmn:EventBasedGateway", + "bpmn:StartEvent", + "bpmn:IntermediateCatchEvent", + "bpmn:IntermediateThrowEvent", + "bpmn:EndEvent", + "bpmn:BoundaryEvent", + "bpmn:CallActivity", + "bpmn:SubProcess", + "bpmn:Process" + ] + }, + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "event", + "isAttr": true, + "type": "String" + }, + { + "name": "script", + "type": "Script" + }, + { + "name": "fields", + "type": "Field", + "isMany": true + } + ] + }, + { + "name": "TaskListener", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "event", + "isAttr": true, + "type": "String" + }, + { + "name": "script", + "type": "Script" + }, + { + "name": "fields", + "type": "Field", + "isMany": true + }, + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "eventDefinitions", + "type": "bpmn:TimerEventDefinition", + "isMany": true + } + ] + }, + { + "name": "FormProperty", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "bpmn:StartEvent", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "type", + "type": "String", + "isAttr": true + }, + { + "name": "required", + "type": "String", + "isAttr": true + }, + { + "name": "readable", + "type": "String", + "isAttr": true + }, + { + "name": "writable", + "type": "String", + "isAttr": true + }, + { + "name": "variable", + "type": "String", + "isAttr": true + }, + { + "name": "expression", + "type": "String", + "isAttr": true + }, + { + "name": "datePattern", + "type": "String", + "isAttr": true + }, + { + "name": "default", + "type": "String", + "isAttr": true + }, + { + "name": "values", + "type": "Value", + "isMany": true + } + ] + }, + { + "name": "FormData", + "superClass": [ "Element" ], + "meta": { + "allowedIn": [ + "bpmn:StartEvent", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "fields", + "type": "FormField", + "isMany": true + }, + { + "name": "businessKey", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "FormField", + "superClass": [ "Element" ], + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "label", + "type": "String", + "isAttr": true + }, + { + "name": "type", + "type": "String", + "isAttr": true + }, + { + "name": "datePattern", + "type": "String", + "isAttr": true + }, + { + "name": "defaultValue", + "type": "String", + "isAttr": true + }, + { + "name": "properties", + "type": "Properties" + }, + { + "name": "validation", + "type": "Validation" + }, + { + "name": "values", + "type": "Value", + "isMany": true + } + ] + }, + { + "name": "Validation", + "superClass": [ "Element" ], + "properties": [ + { + "name": "constraints", + "type": "Constraint", + "isMany": true + } + ] + }, + { + "name": "Constraint", + "superClass": [ "Element" ], + "properties": [ + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "config", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "ConditionalEventDefinition", + "isAbstract": true, + "extends": [ + "bpmn:ConditionalEventDefinition" + ], + "properties": [ + { + "name": "variableName", + "isAttr": true, + "type": "String" + }, + { + "name": "variableEvent", + "isAttr": true, + "type": "String" + } + ] + } + ], + "emumerations": [ ] +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomContextPad.js b/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomContextPad.js new file mode 100644 index 00000000..780b29a4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomContextPad.js @@ -0,0 +1,76 @@ +export default class CustomContextPad { + constructor(config, contextPad, create, elementFactory, injector, translate) { + this.create = create; + this.elementFactory = elementFactory; + this.translate = translate; + //自动摆放位置 + if (config.autoPlace !== false) { + this.autoPlace = injector.get('autoPlace', false); + } + //注册工具 + contextPad.registerProvider(this); + } + getContextPadEntries(element) { + const { + autoPlace, + create, + elementFactory, + translate + } = this; + + function appendUserTask(event, element) { + if (autoPlace) { + const shape = elementFactory.createShape({ type: 'bpmn:UserTask' }); + autoPlace.append(element, shape); + } else { + appendUserTaskStart(event, element); + } + } + + function appendUserTaskStart(event) { + const shape = elementFactory.createShape({ type: 'bpmn:UserTask' }); + create.start(event, shape, element); + } + function appendCallActivityStart(event) { + const shape = elementFactory.createShape({ type: 'bpmn:CallActivity' }); + create.start(event, shape, element); + } + + function appendCallActivity(event, element) { + if (autoPlace) { + const shape = elementFactory.createShape({ type: 'bpmn:CallActivity' }); + autoPlace.append(element, shape); + } else { + appendCallActivityStart(event, element); + } + } + return { + 'append.user-task': { + group: 'model', + className: 'bpmn-icon-user-task', + title: translate('Append ServiceTask'), + action: { + click: appendUserTask, + dragstart: appendUserTaskStart + } + }, + 'append.call-activity':{ + group: 'model', + className: 'bpmn-icon-call-activity', + title: translate('Append CallActivity'), + action: { + click: appendCallActivity, + dragstart: appendCallActivityStart + } + } + }; + } +} +CustomContextPad.$inject = [ + 'config', + 'contextPad', + 'create', + 'elementFactory', + 'injector', + 'translate' +]; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomPalette.js b/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomPalette.js new file mode 100644 index 00000000..a607a1b4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/customControls/CustomPalette.js @@ -0,0 +1,54 @@ +export default class CustomPalette { + constructor(create, elementFactory, palette, translate) { + this.create = create; + this.elementFactory = elementFactory; + this.translate = translate; + palette.registerProvider(this); + } + + getPaletteEntries(element) { + const { + create, + elementFactory, + translate + } = this; + + function createServiceTask(event) { + const shape = elementFactory.createShape({ type: 'bpmn:UserTask' }); + create.start(event, shape); + } + function createCallActivity(event) { + const shape = elementFactory.createShape({ type: 'bpmn:CallActivity' }); + create.start(event, shape); + } + + + return { + 'create.user-task': { + group: 'activity', + className: 'bpmn-icon-user-task', + title: translate('Create UserTask'), + action: { + dragstart: createServiceTask, + click: createServiceTask + } + }, + 'create.call-activity': { + group: 'activity', + className: 'bpmn-icon-call-activity', + title: translate('Create CallActivity'), + action: { + dragstart: createCallActivity, + click: createCallActivity + } + } + } + } +} + +CustomPalette.$inject = [ + 'create', + 'elementFactory', + 'palette', + 'translate' +]; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/customControls/index.js b/ruoyi-ui/xjs-bpmnjs/resources/customControls/index.js new file mode 100644 index 00000000..c1ba21cd --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/customControls/index.js @@ -0,0 +1,8 @@ +import CustomContextPad from './CustomContextPad'; +import CustomPalette from './CustomPalette'; + +export default { + __init__: [ 'customContextPad', 'customPalette' ], + customContextPad: [ 'type', CustomContextPad ], + customPalette: [ 'type', CustomPalette ] +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/customTranslate.js b/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/customTranslate.js new file mode 100644 index 00000000..d55bf8e0 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/customTranslate.js @@ -0,0 +1,12 @@ +import translations from './translationsGerman'; +export default function customTranslate(template, replacements) { + replacements = replacements || {}; + template = translations[template] || template; + return template.replace(/{([^}]+)}/g, function(_, key) { + var str = replacements[key]; + if(translations[replacements[key]] != null && translations [replacements[key]] != 'undefined'){ + str = translations[replacements[key]]; + } + return str || '{' + key + '}'; + }); +} \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/translationsGerman.js b/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/translationsGerman.js new file mode 100644 index 00000000..cfec05cb --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/customTranslate/translationsGerman.js @@ -0,0 +1,239 @@ +export default { + // Labels + 'Activate the global connect tool' : '激活全局连接工具', + 'Append {type}': '追加 {type}', + 'Append EndEvent': '追加 结束事件 ', + 'Append Task':'追加 任务', + 'Append Gateway':'追加 网关', + 'Append Intermediate/Boundary Event':'追加 中间/边界 事件', + 'Add Lane above': '在上面添加道', + 'Divide into two Lanes': '分割成两个道', + 'Divide into three Lanes': '分割成三个道', + 'Add Lane below': '在下面添加道', + 'Append compensation activity': '追加补偿活动', + 'Change type': '修改类型', + 'Connect using Association': '使用关联连接', + 'Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接', + 'Connect using DataInputAssociation': '使用数据输入关联连接', + 'Remove': '移除', + 'Activate the hand tool': '激活抓手工具', + 'Activate the lasso tool': '激活套索工具', + 'Activate the create/remove space tool': '激活创建/删除空间工具', + 'Create expanded SubProcess': '创建扩展子过程', + 'Create IntermediateThrowEvent/BoundaryEvent' : '创建中间抛出事件/边界事件', + 'Create Pool/Participant': '创建池/参与者', + 'Parallel Multi Instance': '并行多重事件', + 'Sequential Multi Instance': '时序多重事件', + 'DataObjectReference':'数据对象参考', + 'DataStoreReference':'数据存储参考', + 'Loop': '循环', + 'Ad-hoc': '即席', + 'Create {type}': '创建 {type}', + 'Create Task':'创建任务', + 'Create StartEvent':'创建开始事件', + 'Create EndEvent':'创建结束事件', + 'Create Group':'创建组', + 'Task': '任务', + 'Send Task': '发送任务', + 'Receive Task': '接收任务', + 'User Task': '用户任务', + 'Manual Task': '手工任务', + 'Business Rule Task': '业务规则任务', + 'Service Task': '服务任务', + 'Script Task': '脚本任务', + 'Call Activity': '调用活动', + 'Sub Process (collapsed)': '子流程(折叠的)', + 'Sub Process (expanded)': '子流程(展开的)', + 'Start Event': '开始事件', + 'StartEvent': '开始事件', + 'Intermediate Throw Event': '中间事件', + 'End Event': '结束事件', + 'EndEvent': '结束事件', + 'Create Gateway': '创建网关', + 'GateWay':'网关', + 'Create Intermediate/Boundary Event': '创建中间/边界事件', + 'Message Start Event': '消息开始事件', + 'Timer Start Event': '定时开始事件', + 'Conditional Start Event': '条件开始事件', + 'Signal Start Event': '信号开始事件', + 'Error Start Event': '错误开始事件', + 'Escalation Start Event': '升级开始事件', + 'Compensation Start Event': '补偿开始事件', + 'Message Start Event (non-interrupting)': '消息开始事件(非中断)', + 'Timer Start Event (non-interrupting)': '定时开始事件(非中断)', + 'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)', + 'Signal Start Event (non-interrupting)': '信号开始事件(非中断)', + 'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)', + 'Message Intermediate Catch Event': '消息中间捕获事件', + 'Message Intermediate Throw Event': '消息中间抛出事件', + 'Timer Intermediate Catch Event': '定时中间捕获事件', + 'Escalation Intermediate Throw Event': '升级中间抛出事件', + 'Conditional Intermediate Catch Event': '条件中间捕获事件', + 'Link Intermediate Catch Event': '链接中间捕获事件', + 'Link Intermediate Throw Event': '链接中间抛出事件', + 'Compensation Intermediate Throw Event': '补偿中间抛出事件', + 'Signal Intermediate Catch Event': '信号中间捕获事件', + 'Signal Intermediate Throw Event': '信号中间抛出事件', + 'Message End Event': '消息结束事件', + 'Escalation End Event': '定时结束事件', + 'Error End Event': '错误结束事件', + 'Cancel End Event': '取消结束事件', + 'Compensation End Event': '补偿结束事件', + 'Signal End Event': '信号结束事件', + 'Terminate End Event': '终止结束事件', + 'Message Boundary Event': '消息边界事件', + 'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)', + 'Timer Boundary Event': '定时边界事件', + 'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)', + 'Escalation Boundary Event': '升级边界事件', + 'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)', + 'Conditional Boundary Event': '条件边界事件', + 'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)', + 'Error Boundary Event': '错误边界事件', + 'Cancel Boundary Event': '取消边界事件', + 'Signal Boundary Event': '信号边界事件', + 'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)', + 'Compensation Boundary Event': '补偿边界事件', + 'Exclusive Gateway': '互斥网关', + 'Parallel Gateway': '并行网关', + 'Inclusive Gateway': '相容网关', + 'Complex Gateway': '复杂网关', + 'Event based Gateway': '事件网关', + 'Transaction': '转运', + 'Sub Process': '子流程', + 'Event Sub Process': '事件子流程', + 'Collapsed Pool': '折叠池', + 'Expanded Pool': '展开池', + // Errors + 'no parent for {element} in {parent}': '在{parent}里,{element}没有父类', + 'no shape type specified': '没有指定的形状类型', + 'flow elements must be children of pools/participants': '流元素必须是池/参与者的子类', + 'out of bounds release': 'out of bounds release', + 'more than {count} child lanes': '子道大于{count} ', + 'element required': '元素不能为空', + 'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范', + 'no diagram to display': '没有可展示的流程图', + 'no process or collaboration to display': '没有可展示的流程/协作', + 'element {element} referenced by {referenced}#{property} not yet drawn': '由{referenced}#{property}引用的{element}元素仍未绘制', + 'already rendered {element}': '{element} 已被渲染', + 'failed to import {element}': '导入{element}失败', + //属性面板的参数 + 'Id':'编号', + 'Name':'名称', + 'General':'常规', + 'Details':'详情', + 'Message Name':'消息名称', + 'Message':'消息', + 'Initiator':'创建者', + 'Asynchronous Continuations':'持续异步', + 'Asynchronous Before':'异步前', + 'Asynchronous After':'异步后', + 'Job Configuration':'工作配置', + 'Exclusive':'排除', + 'Job Priority':'工作优先级', + 'Retry Time Cycle':'重试时间周期', + 'Documentation':'文档', + 'Element Documentation':'元素文档', + 'History Configuration':'历史配置', + 'History Time To Live':'历史的生存时间', + 'Forms':'表单', + 'Form Key':'表单key', + 'Form Fields':'表单字段', + 'Business Key':'业务key', + 'Form Field':'表单字段', + 'ID':'编号', + 'Type':'类型', + 'Label':'名称', + 'Default Value':'默认值', + 'Validation':'校验', + 'Add Constraint':'添加约束', + 'Config':'配置', + 'Properties':'属性', + 'Add Property':'添加属性', + 'Value':'值', + 'Add':'添加', + 'Values':'值', + 'Add Value':'添加值', + 'Listeners':'监听器', + 'Execution Listener':'执行监听', + 'Event Type':'事件类型', + 'Listener Type':'监听器类型', + 'Java Class':'Java类', + 'Expression':'表达式', + 'Must provide a value':'必须提供一个值', + 'Delegate Expression':'代理表达式', + 'Script':'脚本', + 'Script Format':'脚本格式', + 'Script Type':'脚本类型', + 'Inline Script':'内联脚本', + 'External Script':'外部脚本', + 'Resource':'资源', + 'Field Injection':'字段注入', + 'Extensions':'扩展', + 'Input/Output':'输入/输出', + 'Input Parameters':'输入参数', + 'Output Parameters':'输出参数', + 'Parameters':'参数', + 'Output Parameter':'输出参数', + 'Timer Definition Type':'定时器定义类型', + 'Timer Definition':'定时器定义', + 'Date':'日期', + 'Duration':'持续', + 'Cycle':'循环', + 'Signal':'信号', + 'Signal Name':'信号名称', + 'Escalation':'升级', + 'Error':'错误', + 'Link Name':'链接名称', + 'Condition':'条件名称', + 'Variable Name':'变量名称', + 'Variable Event':'变量事件', + 'Specify more than one variable change event as a comma separated list.':'多个变量事件以逗号隔开', + 'Wait for Completion':'等待完成', + 'Activity Ref':'活动参考', + 'Version Tag':'版本标签', + 'Executable':'可执行文件', + 'External Task Configuration':'扩展任务配置', + 'Task Priority':'任务优先级', + 'External':'外部', + 'Connector':'连接器', + 'Must configure Connector':'必须配置连接器', + 'Connector Id':'连接器编号', + 'Implementation':'实现方式', + 'Field Injections':'字段注入', + 'Fields':'字段', + 'Result Variable':'结果变量', + 'Topic':'主题', + 'Configure Connector':'配置连接器', + 'Input Parameter':'输入参数', + 'Assignee':'代理人', + 'Candidate Users':'候选用户', + 'Candidate Groups':'候选组', + 'Due Date':'到期时间', + 'Follow Up Date':'跟踪日期', + 'Priority':'优先级', + 'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00', + 'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00', + 'Variables':'变量', + 'Candidate Starter Configuration':'候选开始配置', + 'Task Listener':'任务监听器', + 'Candidate Starter Groups':'候选开始组', + 'Candidate Starter Users':'候选开始用户', + 'Tasklist Configuration':'任务列表配置', + 'Startable':'启动', + 'Specify more than one group as a comma separated list.':'指定多个组,用逗号分隔', + 'Specify more than one user as a comma separated list.':'指定多个用户,用逗号分隔', + 'This maps to the process definition key.':'这会映射为流程定义的键', + 'CallActivity Type':'调用活动类型', + 'Condition Type':'条件类型', + 'Create UserTask':'创建用户任务', + 'Create CallActivity':'创建调用活动', + 'Called Element':'调用元素', + 'Create DataObjectReference':'创建数据对象引用', + 'Create DataStoreReference':'创建数据存储引用', + 'Multi Instance':'多实例', + 'Loop Cardinality':'实例数量', + 'Collection':'任务参与人列表', + 'Element Variable':'元素变量', + 'Completion Condition':'完成条件' +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/newDiagram.bpmn b/ruoyi-ui/xjs-bpmnjs/resources/newDiagram.bpmn new file mode 100644 index 00000000..0bd0e35d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/newDiagram.bpmn @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesActivator.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesActivator.js new file mode 100644 index 00000000..de087793 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesActivator.js @@ -0,0 +1,67 @@ +'use strict'; + +var DEFAULT_PRIORITY = 1000; + + +/** + * A component that decides upon the visibility / editable + * state of properties in the properties panel. + * + * Implementors must subclass this component and override + * {@link PropertiesActivator#isEntryVisible} and + * {@link PropertiesActivator#isPropertyEditable} to provide + * custom behavior. + * + * @class + * @constructor + * + * @param {EventBus} eventBus + * @param {Number} [priority] at which priority to hook into the activation + */ +function PropertiesActivator(eventBus, priority) { + var self = this; + + priority = priority || DEFAULT_PRIORITY; + + eventBus.on('propertiesPanel.isEntryVisible', priority, function(e) { + return self.isEntryVisible(e.entry, e.element); + }); + + eventBus.on('propertiesPanel.isPropertyEditable', priority, function(e) { + return self.isPropertyEditable(e.entry, e.propertyName, e.element); + }); +} + +PropertiesActivator.$inject = [ 'eventBus' ]; + +module.exports = PropertiesActivator; + + +/** + * Should the given entry be visible for the specified element. + * + * @method PropertiesActivator#isEntryVisible + * + * @param {EntryDescriptor} entry + * @param {ModdleElement} element + * + * @returns {Boolean} + */ +PropertiesActivator.prototype.isEntryVisible = function(entry, element) { + return true; +}; + +/** + * Should the given property be editable for the specified element + * + * @method PropertiesActivator#isPropertyEditable + * + * @param {EntryDescriptor} entry + * @param {String} propertyName + * @param {ModdleElement} element + * + * @returns {Boolean} + */ +PropertiesActivator.prototype.isPropertyEditable = function(entry, propertyName, element) { + return true; +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesPanel.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesPanel.js new file mode 100644 index 00000000..69bcb9dc --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/PropertiesPanel.js @@ -0,0 +1,1267 @@ +'use strict'; + +var escapeHTML = require('./Utils').escapeHTML; + +var domify = require('min-dom').domify, + domQuery = require('min-dom').query, + domQueryAll = require('min-dom').queryAll, + domRemove = require('min-dom').remove, + domClasses = require('min-dom').classes, + domClosest = require('min-dom').closest, + domAttr = require('min-dom').attr, + domDelegate = require('min-dom').delegate, + domMatches = require('min-dom').matches; + +var forEach = require('lodash/forEach'), + filter = require('lodash/filter'), + get = require('lodash/get'), + keys = require('lodash/keys'), + isEmpty = require('lodash/isEmpty'), + isArray = require('lodash/isArray'), + xor = require('lodash/xor'), + debounce = require('lodash/debounce'); + +var updateSelection = require('selection-update'); + +var scrollTabs = require('scroll-tabs').default; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var HIDE_CLASS = 'bpp-hidden'; +var DEBOUNCE_DELAY = 300; + + +function isToggle(node) { + return node.type === 'checkbox' || node.type === 'radio'; +} + +function isSelect(node) { + return node.type === 'select-one'; +} + +function isContentEditable(node) { + return domAttr(node, 'contenteditable'); +} + +function getPropertyPlaceholders(node) { + var selector = 'input[name], textarea[name], [data-value], [contenteditable]'; + var placeholders = domQueryAll(selector, node); + if ((!placeholders || !placeholders.length) && domMatches(node, selector)) { + placeholders = [ node ]; + } + return placeholders; +} + +/** + * Return all active form controls. + * This excludes the invisible controls unless all is true + * + * @param {Element} node + * @param {Boolean} [all=false] + */ +function getFormControls(node, all) { + var controls = domQueryAll('input[name], textarea[name], select[name], [contenteditable]', node); + + if (!controls || !controls.length) { + controls = domMatches(node, 'option') ? [ node ] : controls; + } + + if (!all) { + controls = filter(controls, function(node) { + return !domClosest(node, '.' + HIDE_CLASS); + }); + } + + return controls; +} + +function getFormControlValuesInScope(entryNode) { + var values = {}; + + var controlNodes = getFormControls(entryNode); + + forEach(controlNodes, function(controlNode) { + var value = controlNode.value; + + var name = domAttr(controlNode, 'name') || domAttr(controlNode, 'data-name'); + + // take toggle state into account for radio / checkboxes + if (isToggle(controlNode)) { + if (controlNode.checked) { + if (!domAttr(controlNode, 'value')) { + value = true; + } else { + value = controlNode.value; + } + } else { + value = null; + } + } else + if (isContentEditable(controlNode)) { + value = controlNode.innerText; + } + + if (value !== null) { + // return the actual value + // handle serialization in entry provider + // (ie. if empty string should be serialized or not) + values[name] = value; + } + }); + + return values; + +} + +/** + * Extract input values from entry node + * + * @param {DOMElement} entryNode + * @returns {Object} + */ +function getFormControlValues(entryNode) { + + var values; + + var listContainer = domQuery('[data-list-entry-container]', entryNode); + if (listContainer) { + values = []; + var listNodes = listContainer.children || []; + forEach(listNodes, function(listNode) { + values.push(getFormControlValuesInScope(listNode)); + }); + } else { + values = getFormControlValuesInScope(entryNode); + } + + return values; +} + +/** + * Return true if the given form extracted value equals + * to an old cached version. + * + * @param {Object} value + * @param {Object} oldValue + * @return {Boolean} + */ +function valueEqual(value, oldValue) { + + if (value && !oldValue) { + return false; + } + + var allKeys = keys(value).concat(keys(oldValue)); + + return allKeys.every(function(key) { + return value[key] === oldValue[key]; + }); +} + +/** + * Return true if the given form extracted value(s) + * equal an old cached version. + * + * @param {Array|Object} values + * @param {Array|Object} oldValues + * @return {Boolean} + */ +function valuesEqual(values, oldValues) { + + if (isArray(values)) { + + if (values.length !== oldValues.length) { + return false; + } + + return values.every(function(v, idx) { + return valueEqual(v, oldValues[idx]); + }); + } + + return valueEqual(values, oldValues); +} + +/** + * Return a mapping of { id: entry } for all entries in the given groups in the given tabs. + * + * @param {Object} tabs + * @return {Object} + */ +function extractEntries(tabs) { + return keyBy(flattenDeep(map(flattenDeep(map(tabs, 'groups')), 'entries')), 'id'); +} + +/** + * Return a mapping of { id: group } for all groups in the given tabs. + * + * @param {Object} tabs + * @return {Object} + */ +function extractGroups(tabs) { + return keyBy(flattenDeep(map(tabs, 'groups')), 'id'); +} + +/** + * A properties panel implementation. + * + * To use it provide a `propertiesProvider` component that knows + * about which properties to display. + * + * Properties edit state / visibility can be intercepted + * via a custom {@link PropertiesActivator}. + * + * @class + * @constructor + * + * @param {Object} config + * @param {EventBus} eventBus + * @param {Modeling} modeling + * @param {PropertiesProvider} propertiesProvider + * @param {Canvas} canvas + * @param {CommandStack} commandStack + */ +function PropertiesPanel(config, eventBus, modeling, propertiesProvider, commandStack, canvas) { + + this._eventBus = eventBus; + this._modeling = modeling; + this._commandStack = commandStack; + this._canvas = canvas; + this._propertiesProvider = propertiesProvider; + + this._init(config); +} + +PropertiesPanel.$inject = [ + 'config.propertiesPanel', + 'eventBus', + 'modeling', + 'propertiesProvider', + 'commandStack', + 'canvas' +]; + +module.exports = PropertiesPanel; + + +PropertiesPanel.prototype._init = function(config) { + + var canvas = this._canvas, + eventBus = this._eventBus; + + var self = this; + + /** + * Select the root element once it is added to the canvas + */ + eventBus.on('root.added', function(e) { + var element = e.element; + + if (isImplicitRoot(element)) { + return; + } + + self.update(element); + }); + + eventBus.on('selection.changed', function(e) { + var newElement = e.newSelection[0]; + + var rootElement = canvas.getRootElement(); + + if (isImplicitRoot(rootElement)) { + return; + } + + self.update(newElement); + }); + + // add / update tab-bar scrolling + eventBus.on([ + 'propertiesPanel.changed', + 'propertiesPanel.resized' + ], function(event) { + + var tabBarNode = domQuery('.bpp-properties-tab-bar', self._container); + + if (!tabBarNode) { + return; + } + + var scroller = scrollTabs.get(tabBarNode); + + if (!scroller) { + + // we did not initialize yet, do that + // now and make sure we select the active + // tab on scroll update + scroller = scrollTabs(tabBarNode, { + selectors: { + tabsContainer: '.bpp-properties-tabs-links', + tab: '.bpp-properties-tabs-links li', + ignore: '.bpp-hidden', + active: '.bpp-active' + } + }); + + + scroller.on('scroll', function(newActiveNode, oldActiveNode, direction) { + + var linkNode = domQuery('[data-tab-target]', newActiveNode); + + var tabId = domAttr(linkNode, 'data-tab-target'); + + self.activateTab(tabId); + }); + } + + // react on tab changes and or tabContainer resize + // and make sure the active tab is shown completely + scroller.update(); + }); + + eventBus.on('elements.changed', function(e) { + + var current = self._current; + var element = current && current.element; + + if (element) { + if (e.elements.indexOf(element) !== -1) { + self.update(element); + } + } + }); + + eventBus.on('elementTemplates.changed', function() { + var current = self._current; + var element = current && current.element; + + if (element) { + self.update(element); + } + }); + + eventBus.on('diagram.destroy', function() { + self.detach(); + }); + + this._container = domify(''); + + this._bindListeners(this._container); + + if (config && config.parent) { + this.attachTo(config.parent); + } +}; + + +PropertiesPanel.prototype.attachTo = function(parentNode) { + + if (!parentNode) { + throw new Error('parentNode required'); + } + + // ensure we detach from the + // previous, old parent + this.detach(); + + // unwrap jQuery if provided + if (parentNode.get && parentNode.constructor.prototype.jquery) { + parentNode = parentNode.get(0); + } + + if (typeof parentNode === 'string') { + parentNode = domQuery(parentNode); + } + + var container = this._container; + + parentNode.appendChild(container); + + this._emit('attach'); +}; + +PropertiesPanel.prototype.detach = function() { + + var container = this._container, + parentNode = container.parentNode; + + if (!parentNode) { + return; + } + + this._emit('detach'); + + parentNode.removeChild(container); +}; + + +/** + * Select the given tab within the properties panel. + * + * @param {Object|String} tab + */ +PropertiesPanel.prototype.activateTab = function(tab) { + + var tabId = typeof tab === 'string' ? tab : tab.id; + + var current = this._current; + + var panelNode = current.panel; + + var allTabNodes = domQueryAll('.bpp-properties-tab', panelNode), + allTabLinkNodes = domQueryAll('.bpp-properties-tab-link', panelNode); + + forEach(allTabNodes, function(tabNode) { + + var currentTabId = domAttr(tabNode, 'data-tab'); + + domClasses(tabNode).toggle('bpp-active', tabId === currentTabId); + }); + + forEach(allTabLinkNodes, function(tabLinkNode) { + + var tabLink = domQuery('[data-tab-target]', tabLinkNode), + currentTabId = domAttr(tabLink, 'data-tab-target'); + + domClasses(tabLinkNode).toggle('bpp-active', tabId === currentTabId); + }); +}; + +/** + * Update the DOM representation of the properties panel + */ +PropertiesPanel.prototype.update = function(element) { + var current = this._current; + + // no actual selection change + var needsCreate = true; + + if (typeof element === 'undefined') { + + // use RootElement of BPMN diagram to generate properties panel if no element is selected + element = this._canvas.getRootElement(); + } + + var newTabs = this._propertiesProvider.getTabs(element); + + if (current && current.element === element) { + // see if we can reuse the existing panel + + needsCreate = this._entriesChanged(current, newTabs); + } + + if (needsCreate) { + + if (current) { + + // get active tab from the existing panel before remove it + var activeTabNode = domQuery('.bpp-properties-tab.bpp-active', current.panel); + + var activeTabId; + if (activeTabNode) { + activeTabId = domAttr(activeTabNode, 'data-tab'); + } + + // remove old panel + domRemove(current.panel); + } + + this._current = this._create(element, newTabs); + + // activate the saved active tab from the remove panel or the first tab + (activeTabId) ? this.activateTab(activeTabId) : this.activateTab(this._current.tabs[0]); + + } + + if (this._current) { + // make sure correct tab contents are visible + this._updateActivation(this._current); + + } + + this._emit('changed'); +}; + + +/** + * Returns true if one of two groups has different entries than the other. + * + * @param {Object} current + * @param {Object} newTabs + * @return {Boolean} + */ +PropertiesPanel.prototype._entriesChanged = function(current, newTabs) { + + var oldEntryIds = keys(current.entries), + newEntryIds = keys(extractEntries(newTabs)); + + return !isEmpty(xor(oldEntryIds, newEntryIds)); +}; + +PropertiesPanel.prototype._emit = function(event) { + this._eventBus.fire('propertiesPanel.' + event, { panel: this, current: this._current }); +}; + +PropertiesPanel.prototype._bindListeners = function(container) { + + var self = this; + + // handles a change for a given event + var handleChange = function handleChange(event) { + + // see if we handle a change inside a [data-entry] element. + // if not, drop out + var inputNode = event.delegateTarget, + entryNode = domClosest(inputNode, '[data-entry]'), + entryId, entry; + + // change from outside a [data-entry] element, simply ignore + if (!entryNode) { + return; + } + + entryId = domAttr(entryNode, 'data-entry'); + entry = self.getEntry(entryId); + + var values = getFormControlValues(entryNode); + + if (event.type === 'change') { + + // - if the "data-on-change" attribute is present and a value is changed, + // then the associated action is performed. + // - if the associated action returns "true" then an update to the business + // object is done + // - if it does not return "true", then only the DOM content is updated + var onChangeAction = domAttr(inputNode, 'data-on-change'); + + if (onChangeAction) { + var isEntryDirty = self.executeAction(entry, entryNode, onChangeAction, event); + + if (!isEntryDirty) { + return self.update(self._current.element); + } + } + } + self.applyChanges(entry, values, entryNode); + self.updateState(entry, entryNode); + }; + + // debounce update only elements that are target of key events, + // i.e. INPUT and TEXTAREA. SELECTs will trigger an immediate update anyway. + domDelegate.bind(container, 'input, textarea, [contenteditable]', 'input', debounce(handleChange, DEBOUNCE_DELAY)); + domDelegate.bind(container, 'input, textarea, select, [contenteditable]', 'change', handleChange); + + // handle key events + domDelegate.bind(container, 'select', 'keydown', function(e) { + + // DEL + if (e.keyCode === 46) { + e.stopPropagation(); + e.preventDefault(); + } + }); + + domDelegate.bind(container, '[data-action]', 'click', function onClick(event) { + + // triggers on all inputs + var inputNode = event.delegateTarget, + entryNode = domClosest(inputNode, '[data-entry]'); + + var actionId = domAttr(inputNode, 'data-action'), + entryId = domAttr(entryNode, 'data-entry'); + + var entry = self.getEntry(entryId); + + var isEntryDirty = self.executeAction(entry, entryNode, actionId, event); + + if (isEntryDirty) { + var values = getFormControlValues(entryNode); + + self.applyChanges(entry, values, entryNode); + } + + self.updateState(entry, entryNode); + }); + + function handleInput(event, element) { + // triggers on all inputs + var inputNode = event.delegateTarget; + + var entryNode = domClosest(inputNode, '[data-entry]'); + + // only work on data entries + if (!entryNode) { + return; + } + + var eventHandlerId = domAttr(inputNode, 'data-blur'), + entryId = domAttr(entryNode, 'data-entry'); + + var entry = self.getEntry(entryId); + + var isEntryDirty = self.executeAction(entry, entryNode, eventHandlerId, event); + + if (isEntryDirty) { + var values = getFormControlValues(entryNode); + + self.applyChanges(entry, values, entryNode); + } + + self.updateState(entry, entryNode); + } + + domDelegate.bind(container, '[data-blur]', 'blur', handleInput, true); + + // make tab links interactive + domDelegate.bind(container, '.bpp-properties-tabs-links [data-tab-target]', 'click', function(event) { + event.preventDefault(); + + var delegateTarget = event.delegateTarget; + + var tabId = domAttr(delegateTarget, 'data-tab-target'); + + // activate tab on link click + self.activateTab(tabId); + }); + +}; + +PropertiesPanel.prototype.updateState = function(entry, entryNode) { + this.updateShow(entry, entryNode); + this.updateDisable(entry, entryNode); +}; + +/** + * Update the visibility of the entry node in the DOM + */ +PropertiesPanel.prototype.updateShow = function(entry, node) { + + var current = this._current; + + if (!current) { + return; + } + + var showNodes = domQueryAll('[data-show]', node) || []; + + forEach(showNodes, function(showNode) { + + var expr = domAttr(showNode, 'data-show'); + var fn = get(entry, expr); + if (fn) { + var scope = domClosest(showNode, '[data-scope]') || node; + var shouldShow = fn(current.element, node, showNode, scope) || false; + if (shouldShow) { + domClasses(showNode).remove(HIDE_CLASS); + } else { + domClasses(showNode).add(HIDE_CLASS); + } + } + }); +}; + +/** + * Evaluates a given function. If it returns true, then the + * node is marked as "disabled". + */ +PropertiesPanel.prototype.updateDisable = function(entry, node) { + var current = this._current; + + if (!current) { + return; + } + + var nodes = domQueryAll('[data-disable]', node) || []; + + forEach(nodes, function(currentNode) { + var expr = domAttr(currentNode, 'data-disable'); + var fn = get(entry, expr); + if (fn) { + var scope = domClosest(currentNode, '[data-scope]') || node; + var shouldDisable = fn(current.element, node, currentNode, scope) || false; + domAttr(currentNode, 'disabled', shouldDisable ? '' : null); + } + }); +}; + +PropertiesPanel.prototype.executeAction = function(entry, entryNode, actionId, event) { + var current = this._current; + + if (!current) { + return; + } + + var fn = get(entry, actionId); + if (fn) { + var scopeNode = domClosest(event.target, '[data-scope]') || entryNode; + return fn.apply(entry, [ current.element, entryNode, event, scopeNode ]); + } +}; + +/** + * Apply changes to the business object by executing a command + */ +PropertiesPanel.prototype.applyChanges = function(entry, values, containerElement) { + + var element = this._current.element; + + // ensure we only update the model if we got dirty changes + if (valuesEqual(values, entry.oldValues)) { + return; + } + + var command = entry.set(element, values, containerElement); + + var commandToExecute; + + if (isArray(command)) { + if (command.length) { + commandToExecute = { + cmd: 'properties-panel.multi-command-executor', + context: flattenDeep(command) + }; + } + } else { + commandToExecute = command; + } + + if (commandToExecute) { + this._commandStack.execute(commandToExecute.cmd, commandToExecute.context || { element : element }); + } else { + this.update(element); + } +}; + + +/** + * apply validation errors in the DOM and show or remove an error message near the entry node. + */ +PropertiesPanel.prototype.applyValidationErrors = function(validationErrors, entryNode) { + + var valid = true; + + var controlNodes = getFormControls(entryNode, true); + + forEach(controlNodes, function(controlNode) { + + var name = domAttr(controlNode, 'name') || domAttr(controlNode, 'data-name'); + + var error = validationErrors && validationErrors[name]; + + var errorMessageNode = domQuery('.bpp-error-message', controlNode.parentNode); + + if (error) { + valid = false; + + if (!errorMessageNode) { + errorMessageNode = domify(''); + + domClasses(errorMessageNode).add('bpp-error-message'); + + // insert errorMessageNode after controlNode + controlNode.parentNode.insertBefore(errorMessageNode, controlNode.nextSibling); + } + + errorMessageNode.textContent = error; + + domClasses(controlNode).add('invalid'); + } else { + domClasses(controlNode).remove('invalid'); + + if (errorMessageNode) { + controlNode.parentNode.removeChild(errorMessageNode); + } + } + }); + + return valid; +}; + + +/** + * Check if the entry contains valid input + */ +PropertiesPanel.prototype.validate = function(entry, values, entryNode) { + var self = this; + + var current = this._current; + + var valid = true; + + entryNode = entryNode || domQuery('[data-entry="' + entry.id + '"]', current.panel); + + if (values instanceof Array) { + var listContainer = domQuery('[data-list-entry-container]', entryNode), + listEntryNodes = listContainer.children || []; + + // create new elements + for (var i = 0; i < values.length; i++) { + var listValue = values[i]; + + if (entry.validateListItem) { + + var validationErrors = entry.validateListItem(current.element, listValue, entryNode, i), + listEntryNode = listEntryNodes[i]; + + valid = self.applyValidationErrors(validationErrors, listEntryNode) && valid; + } + } + } else { + if (entry.validate) { + this.validationErrors = entry.validate(current.element, values, entryNode); + + valid = self.applyValidationErrors(this.validationErrors, entryNode) && valid; + } + } + + return valid; +}; + +PropertiesPanel.prototype.getEntry = function(id) { + return this._current && this._current.entries[id]; +}; + +var flattenDeep = require('lodash/flattenDeep'), + keyBy = require('lodash/keyBy'), + map = require('lodash/map'); + +PropertiesPanel.prototype._create = function(element, tabs) { + + if (!element) { + return null; + } + + var containerNode = this._container; + + var panelNode = this._createPanel(element, tabs); + + containerNode.appendChild(panelNode); + + var entries = extractEntries(tabs); + var groups = extractGroups(tabs); + + return { + tabs: tabs, + groups: groups, + entries: entries, + element: element, + panel: panelNode + }; +}; + +/** + * Update variable parts of the entry node on element changes. + * + * @param {djs.model.Base} element + * @param {EntryDescriptor} entry + * @param {Object} values + * @param {HTMLElement} entryNode + * @param {Number} idx + */ +PropertiesPanel.prototype._bindTemplate = function(element, entry, values, entryNode, idx) { + + var eventBus = this._eventBus; + + function isPropertyEditable(entry, propertyName) { + return eventBus.fire('propertiesPanel.isPropertyEditable', { + entry: entry, + propertyName: propertyName, + element: element + }); + } + + var inputNodes = getPropertyPlaceholders(entryNode); + + forEach(inputNodes, function(node) { + + var name, + newValue, + editable; + + // we deal with an input element + if ('value' in node || isContentEditable(node) === 'true') { + name = domAttr(node, 'name') || domAttr(node, 'data-name'); + newValue = values[name]; + + editable = isPropertyEditable(entry, name); + if (editable && entry.editable) { + editable = entry.editable(element, entryNode, node, name, newValue, idx); + } + + domAttr(node, 'readonly', editable ? null : ''); + domAttr(node, 'disabled', editable ? null : ''); + + // take full control over setting the value + // and possibly updating the input in entry#setControlValue + if (entry.setControlValue) { + entry.setControlValue(element, entryNode, node, name, newValue, idx); + } else if (isToggle(node)) { + setToggleValue(node, newValue); + } else if (isSelect(node)) { + setSelectValue(node, newValue); + } else { + setInputValue(node, newValue); + } + } + + // we deal with some non-editable html element + else { + name = domAttr(node, 'data-value'); + newValue = values[name]; + if (entry.setControlValue) { + entry.setControlValue(element, entryNode, node, name, newValue, idx); + } else { + setTextValue(node, newValue); + } + } + }); +}; + +PropertiesPanel.prototype._updateActivation = function(current) { + var self = this; + + var eventBus = this._eventBus; + + var element = current.element; + + function isEntryVisible(entry) { + return eventBus.fire('propertiesPanel.isEntryVisible', { + entry: entry, + element: element + }); + } + + function isGroupVisible(group, element, groupNode) { + if (typeof group.enabled === 'function') { + return group.enabled(element, groupNode); + } else { + return true; + } + } + + function isTabVisible(tab, element) { + if (typeof tab.enabled === 'function') { + return tab.enabled(element); + } else { + return true; + } + } + + function toggleVisible(node, visible) { + domClasses(node).toggle(HIDE_CLASS, !visible); + } + + // check whether the active tab is visible + // if not: set the first tab as active tab + function checkActiveTabVisibility(node, visible) { + var isActive = domClasses(node).has('bpp-active'); + if (!visible && isActive) { + self.activateTab(current.tabs[0]); + } + } + + function updateLabel(element, selector, text) { + var labelNode = domQuery(selector, element); + + if (!labelNode) { + return; + } + + labelNode.textContent = text; + } + + var panelNode = current.panel; + + forEach(current.tabs, function(tab) { + + var tabNode = domQuery('[data-tab=' + tab.id + ']', panelNode); + var tabLinkNode = domQuery('[data-tab-target=' + tab.id + ']', panelNode).parentNode; + + var tabVisible = false; + + forEach(tab.groups, function(group) { + + var groupVisible = false; + + var groupNode = domQuery('[data-group=' + group.id + ']', tabNode); + + forEach(group.entries, function(entry) { + + var entryNode = domQuery('[data-entry="' + entry.id + '"]', groupNode); + + var entryVisible = isEntryVisible(entry); + + groupVisible = groupVisible || entryVisible; + + toggleVisible(entryNode, entryVisible); + + var values = 'get' in entry ? entry.get(element, entryNode) : {}; + + if (values instanceof Array) { + var listEntryContainer = domQuery('[data-list-entry-container]', entryNode); + var existingElements = listEntryContainer.children || []; + + for (var i = 0; i < values.length; i++) { + var listValue = values[i]; + var listItemNode = existingElements[i]; + if (!listItemNode) { + listItemNode = domify(entry.createListEntryTemplate(listValue, i, listEntryContainer)); + listEntryContainer.appendChild(listItemNode); + } + domAttr(listItemNode, 'data-index', i); + + self._bindTemplate(element, entry, listValue, listItemNode, i); + } + + var entriesToRemove = existingElements.length - values.length; + + for (var j = 0; j < entriesToRemove; j++) { + // remove orphaned element + listEntryContainer.removeChild(listEntryContainer.lastChild); + } + + } else { + self._bindTemplate(element, entry, values, entryNode); + } + + // update conditionally visible elements + self.updateState(entry, entryNode); + self.validate(entry, values, entryNode); + + // remember initial state for later dirty checking + entry.oldValues = getFormControlValues(entryNode); + }); + + if (typeof group.label === 'function') { + updateLabel(groupNode, '.group-label', group.label(element, groupNode)); + } + + groupVisible = groupVisible && isGroupVisible(group, element, groupNode); + + tabVisible = tabVisible || groupVisible; + + toggleVisible(groupNode, groupVisible); + }); + + tabVisible = tabVisible && isTabVisible(tab, element); + + toggleVisible(tabNode, tabVisible); + toggleVisible(tabLinkNode, tabVisible); + + checkActiveTabVisibility(tabNode, tabVisible); + }); + + // inject elements id into header + updateLabel(panelNode, '[data-label-id]', getBusinessObject(element).id || ''); +}; + +PropertiesPanel.prototype._createPanel = function(element, tabs) { + var self = this; + + var panelNode = domify(''), + headerNode = domify('' + + '' + + '' + + '' + + 'Search' + + '' + + ''), + tabBarNode = domify(''), + tabLinksNode = domify(''), + tabContainerNode = domify(''); + + panelNode.appendChild(headerNode); + + forEach(tabs, function(tab, tabIndex) { + + if (!tab.id) { + throw new Error('tab must have an id'); + } + + var tabNode = domify(''), + tabLinkNode = domify('' + + '' + escapeHTML(tab.label) + '' + + ''); + + var groups = tab.groups; + + forEach(groups, function(group) { + + if (!group.id) { + throw new Error('group must have an id'); + } + + var groupNode = domify('' + + '' + + '' + escapeHTML(group.label) + '' + + ''); + + groupNode.querySelector('.group-toggle').addEventListener('click', function(evt) { + domClasses(groupNode).toggle('group-closed'); + evt.preventDefault(); + evt.stopPropagation(); + }); + groupNode.addEventListener('click', function(evt) { + if (!evt.defaultPrevented && domClasses(groupNode).has('group-closed')) { + domClasses(groupNode).remove('group-closed'); + } + }); + + forEach(group.entries, function(entry) { + + if (!entry.id) { + throw new Error('entry must have an id'); + } + + var html = entry.html; + + if (typeof html === 'string') { + html = domify(html); + } + + // unwrap jquery + if (html.get && html.constructor.prototype.jquery) { + html = html.get(0); + } + + var entryNode = domify(''); + + forEach(entry.cssClasses || [], function(cssClass) { + domClasses(entryNode).add(cssClass); + }); + + entryNode.appendChild(html); + + groupNode.appendChild(entryNode); + + // update conditionally visible elements + self.updateState(entry, entryNode); + }); + + tabNode.appendChild(groupNode); + }); + + tabLinksNode.appendChild(tabLinkNode); + tabContainerNode.appendChild(tabNode); + }); + + tabBarNode.appendChild(tabLinksNode); + + panelNode.appendChild(tabBarNode); + panelNode.appendChild(tabContainerNode); + + return panelNode; +}; + + + +function setInputValue(node, value) { + + var contentEditable = isContentEditable(node); + + var oldValue = contentEditable ? node.innerText : node.value; + + var selection; + + // prevents input fields from having the value 'undefined' + if (value === undefined) { + value = ''; + } + + if (oldValue === value) { + return; + } + + // update selection on undo/redo + if (document.activeElement === node) { + selection = updateSelection(getSelection(node), oldValue, value); + } + + if (contentEditable) { + node.innerText = value; + } else { + node.value = value; + } + + if (selection) { + setSelection(node, selection); + } +} + +function setSelectValue(node, value) { + if (value !== undefined) { + node.value = value; + } +} + +function setToggleValue(node, value) { + var nodeValue = node.value; + + node.checked = (value === nodeValue) || (!domAttr(node, 'value') && value); +} + +function setTextValue(node, value) { + node.textContent = value; +} + +function getSelection(node) { + + return isContentEditable(node) ? getContentEditableSelection(node) : { + start: node.selectionStart, + end: node.selectionEnd + }; +} + +function getContentEditableSelection(node) { + + var selection = window.getSelection(); + + var focusNode = selection.focusNode, + focusOffset = selection.focusOffset, + anchorOffset = selection.anchorOffset; + + if (!focusNode) { + throw new Error('not selected'); + } + + // verify we have selection on the current element + if (!node.contains(focusNode)) { + throw new Error('not selected'); + } + + return { + start: Math.min(focusOffset, anchorOffset), + end: Math.max(focusOffset, anchorOffset) + }; +} + +function setSelection(node, selection) { + + if (isContentEditable(node)) { + setContentEditableSelection(node, selection); + } else { + node.selectionStart = selection.start; + node.selectionEnd = selection.end; + } +} + +function setContentEditableSelection(node, selection) { + + var focusNode, + domRange, + domSelection; + + focusNode = node.firstChild || node, + domRange = document.createRange(); + domRange.setStart(focusNode, selection.start); + domRange.setEnd(focusNode, selection.end); + + domSelection = window.getSelection(); + domSelection.removeAllRanges(); + domSelection.addRange(domRange); +} + +function isImplicitRoot(element) { + return element.id === '__implicitroot'; +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/Utils.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/Utils.js new file mode 100644 index 00000000..4632429c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/Utils.js @@ -0,0 +1,252 @@ +'use strict'; + +var domQuery = require('min-dom').query, + domClear = require('min-dom').clear, + is = require('bpmn-js/lib/util/ModelUtil').is, + forEach = require('lodash/forEach'), + domify = require('min-dom').domify, + Ids = require('ids').default; + +var SPACE_REGEX = /\s/; + +// for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar +var QNAME_REGEX = /^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i; + +// for ID validation as per BPMN Schema (QName - Namespace) +var ID_REGEX = /^[a-z_][\w-.]*$/i; + +var PLACEHOLDER_REGEX = /\$\{([^}]*)\}/g; + +var HTML_ESCAPE_MAP = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' +}; + +function selectedOption(selectBox) { + if (selectBox.selectedIndex >= 0) { + return selectBox.options[selectBox.selectedIndex].value; + } +} + +module.exports.selectedOption = selectedOption; + + +function selectedType(elementSyntax, inputNode) { + var typeSelect = domQuery(elementSyntax, inputNode); + return selectedOption(typeSelect); +} + +module.exports.selectedType = selectedType; + + +/** + * Retrieve the root element the document this + * business object is contained in. + * + * @return {ModdleElement} + */ +function getRoot(businessObject) { + var parent = businessObject; + while (parent.$parent) { + parent = parent.$parent; + } + return parent; +} + +module.exports.getRoot = getRoot; + + +/** + * filters all elements in the list which have a given type. + * removes a new list + */ +function filterElementsByType(objectList, type) { + var list = objectList || []; + var result = []; + forEach(list, function(obj) { + if (is(obj, type)) { + result.push(obj); + } + }); + return result; +} + +module.exports.filterElementsByType = filterElementsByType; + + +function findRootElementsByType(businessObject, referencedType) { + var root = getRoot(businessObject); + + return filterElementsByType(root.rootElements, referencedType); +} + +module.exports.findRootElementsByType = findRootElementsByType; + + +function removeAllChildren(domElement) { + while (domElement.firstChild) { + domElement.removeChild(domElement.firstChild); + } +} + +module.exports.removeAllChildren = removeAllChildren; + + +/** + * adds an empty option to the list + */ +function addEmptyParameter(list) { + return list.push({ 'label': '', 'value': '', 'name': '' }); +} + +module.exports.addEmptyParameter = addEmptyParameter; + + +/** + * returns a list with all root elements for the given parameter 'referencedType' + */ +function refreshOptionsModel(businessObject, referencedType) { + var model = []; + var referableObjects = findRootElementsByType(businessObject, referencedType); + forEach(referableObjects, function(obj) { + model.push({ + label: (obj.name || '') + ' (id='+obj.id+')', + value: obj.id, + name: obj.name + }); + }); + return model; +} + +module.exports.refreshOptionsModel = refreshOptionsModel; + + +/** + * fills the drop down with options + */ +function updateOptionsDropDown(domSelector, businessObject, referencedType, entryNode) { + var options = refreshOptionsModel(businessObject, referencedType); + addEmptyParameter(options); + var selectBox = domQuery(domSelector, entryNode); + domClear(selectBox); + + forEach(options, function(option) { + var optionEntry = domify('' + escapeHTML(option.label) + ''); + selectBox.appendChild(optionEntry); + }); + return options; +} + +module.exports.updateOptionsDropDown = updateOptionsDropDown; + + +/** + * checks whether the id value is valid + * + * @param {ModdleElement} bo + * @param {String} idValue + * @param {Function} translate + * + * @return {String} error message + */ +function isIdValid(bo, idValue, translate) { + var assigned = bo.$model.ids.assigned(idValue); + + var idExists = assigned && assigned !== bo; + + if (!idValue || idExists) { + return translate('Element must have an unique id.'); + } + + return validateId(idValue, translate); +} + +module.exports.isIdValid = isIdValid; + + +function validateId(idValue, translate) { + + idValue = stripPlaceholders(idValue); + + if (containsSpace(idValue)) { + return translate('Id must not contain spaces.'); + } + + if (!ID_REGEX.test(idValue)) { + + if (QNAME_REGEX.test(idValue)) { + return translate('Id must not contain prefix.'); + } + + return translate('Id must be a valid QName.'); + } +} + +module.exports.validateId = validateId; + + +function containsSpace(value) { + return SPACE_REGEX.test(value); +} + +module.exports.containsSpace = containsSpace; + + +function stripPlaceholders(idValue) { + + // replace expression e.g. ${VERSION_TAG} + // use only the content between ${} + // for the REGEX check + return idValue.replace(PLACEHOLDER_REGEX, '$1'); +} + +/** + * generate a semantic id with given prefix + */ +function nextId(prefix) { + var ids = new Ids([32,32,1]); + + return ids.nextPrefixed(prefix); +} + +module.exports.nextId = nextId; + + +function triggerClickEvent(element) { + var evt; + var eventType = 'click'; + + if (document.createEvent) { + try { + // Chrome, Safari, Firefox + evt = new MouseEvent((eventType), { view: window, bubbles: true, cancelable: true }); + } catch (e) { + // IE 11, PhantomJS (wat!) + evt = document.createEvent('MouseEvent'); + + evt.initEvent((eventType), true, true); + } + return element.dispatchEvent(evt); + } else { + // Welcome IE + evt = document.createEventObject(); + + return element.fireEvent('on' + eventType, evt); + } +} + +module.exports.triggerClickEvent = triggerClickEvent; + + +function escapeHTML(str) { + str = '' + str; + + return str && str.replace(/[&<>"']/g, function(match) { + return HTML_ESCAPE_MAP[match]; + }); +} + +module.exports.escapeHTML = escapeHTML; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateAndReferenceHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateAndReferenceHandler.js new file mode 100644 index 00000000..8850c1c1 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateAndReferenceHandler.js @@ -0,0 +1,101 @@ +'use strict'; + +var elementHelper = require('../helper/ElementHelper'); + +/** + * A handler capable of creating a new element under a provided parent + * and updating / creating a reference to it in one atomic action. + * + * @class + * @constructor + */ +function CreateAndReferenceElementHandler(elementRegistry, bpmnFactory) { + this._elementRegistry = elementRegistry; + this._bpmnFactory = bpmnFactory; +} + +CreateAndReferenceElementHandler.$inject = [ 'elementRegistry', 'bpmnFactory' ]; + +module.exports = CreateAndReferenceElementHandler; + + +// api //////////////////// + +/** + * Creates a new element under a provided parent and updates / creates a reference to it in + * one atomic action. + * + * @method CreateAndReferenceElementHandler#execute + * + * @param {Object} context + * @param {djs.model.Base} context.element which is the context for the reference + * @param {moddle.referencingObject} context.referencingObject the object which creates the reference + * @param {String} context.referenceProperty the property of the referencingObject which makes the reference + * @param {moddle.newObject} context.newObject the new object to add + * @param {moddle.newObjectContainer} context.newObjectContainer the container for the new object + * + * @returns {Array} the updated element + */ +CreateAndReferenceElementHandler.prototype.execute = function(context) { + + var referencingObject = ensureNotNull(context.referencingObject, 'referencingObject'), + referenceProperty = ensureNotNull(context.referenceProperty, 'referenceProperty'), + newObject = ensureNotNull(context.newObject, 'newObject'), + newObjectContainer = ensureNotNull(context.newObjectContainer, 'newObjectContainer'), + newObjectParent = ensureNotNull(context.newObjectParent, 'newObjectParent'), + changed = [ context.element ]; // this will not change any diagram-js elements + + // create new object + var referencedObject = elementHelper + .createElement(newObject.type, newObject.properties, newObjectParent, this._bpmnFactory); + context.referencedObject = referencedObject; + + // add to containing list + newObjectContainer.push(referencedObject); + + // adjust reference attribute + context.previousReference = referencingObject[referenceProperty]; + referencingObject[referenceProperty] = referencedObject; + + context.changed = changed; + + // indicate changed on objects affected by the update + return changed; +}; + +/** + * Reverts the update + * + * @method CreateAndReferenceElementHandler#revert + * + * @param {Object} context + * + * @returns {djs.mode.Base} the updated element + */ +CreateAndReferenceElementHandler.prototype.revert = function(context) { + + var referencingObject = context.referencingObject, + referenceProperty = context.referenceProperty, + previousReference = context.previousReference, + referencedObject = context.referencedObject, + newObjectContainer = context.newObjectContainer; + + // reset reference + referencingObject.set(referenceProperty, previousReference); + + // remove new element + newObjectContainer.splice(newObjectContainer.indexOf(referencedObject), 1); + + return context.changed; +}; + + + +// helpers ////////////// + +function ensureNotNull(prop, name) { + if (!prop) { + throw new Error(name + ' required'); + } + return prop; +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateBusinessObjectListHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateBusinessObjectListHandler.js new file mode 100644 index 00000000..2870bff7 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/CreateBusinessObjectListHandler.js @@ -0,0 +1,110 @@ +'use strict'; + +var forEach = require('lodash/forEach'); + +var elementHelper = require('../helper/ElementHelper'); + +/** + * A handler that implements a BPMN 2.0 property update + * for business objects which are not represented in the + * diagram. + * + * This is useful in the context of the properties panel in + * order to update child elements of elements visible in + * the diagram. + * + * Example: perform an update of a specific event definition + * of an intermediate event. + * + * @class + * @constructor + */ +function CreateBusinessObjectListHandler(elementRegistry, bpmnFactory) { + this._elementRegistry = elementRegistry; + this._bpmnFactory = bpmnFactory; +} + +CreateBusinessObjectListHandler.$inject = [ 'elementRegistry', 'bpmnFactory' ]; + +module.exports = CreateBusinessObjectListHandler; + +function ensureNotNull(prop, name) { + if (!prop) { + throw new Error(name + ' required'); + } + return prop; + +} +function ensureList(prop, name) { + if (!prop || Object.prototype.toString.call(prop) !== '[object Array]') { + throw new Error(name + ' needs to be a list'); + } + return prop; +} + +// api ///////////////////////////////////////////// + +/** + * Creates a new element under a provided parent and updates / creates a reference to it in + * one atomic action. + * + * @method CreateBusinessObjectListHandler#execute + * + * @param {Object} context + * @param {djs.model.Base} context.element which is the context for the reference + * @param {moddle.referencingObject} context.referencingObject the object which creates the reference + * @param {String} context.referenceProperty the property of the referencingObject which makes the reference + * @param {moddle.newObject} context.newObject the new object to add + * @param {moddle.newObjectContainer} context.newObjectContainer the container for the new object + * + * @return {Array} the updated element + */ +CreateBusinessObjectListHandler.prototype.execute = function(context) { + + var currentObject = ensureNotNull(context.currentObject, 'currentObject'), + propertyName = ensureNotNull(context.propertyName, 'propertyName'), + newObjects = ensureList(context.newObjects, 'newObjects'), + changed = [ context.element ]; // this will not change any diagram-js elements + + + var childObjects = []; + var self = this; + + // create new array of business objects + forEach(newObjects, function(obj) { + var element = elementHelper.createElement(obj.type, obj.properties, currentObject, self._bpmnFactory); + + childObjects.push(element); + }); + context.childObject = childObjects; + + // adjust array reference in the parent business object + context.previousChilds = currentObject[propertyName]; + currentObject[propertyName] = childObjects; + + context.changed = changed; + + // indicate changed on objects affected by the update + return changed; +}; + +/** + * Reverts the update + * + * @method CreateBusinessObjectListHandler#revert + * + * @param {Object} context + * + * @return {djs.mode.Base} the updated element + */ +CreateBusinessObjectListHandler.prototype.revert = function(context) { + + var currentObject = context.currentObject, + propertyName = context.propertyName, + previousChilds = context.previousChilds; + + // remove new element + currentObject.set(propertyName, previousChilds); + + return context.changed; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/MultiCommandHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/MultiCommandHandler.js new file mode 100644 index 00000000..79634a2e --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/MultiCommandHandler.js @@ -0,0 +1,32 @@ +'use strict'; + +var forEach = require('lodash/forEach'); + +/** + * A handler that combines and executes multiple commands. + * + * All updates are bundled on the command stack and executed in one step. + * This also makes it possible to revert the changes in one step. + * + * Example use case: remove the camunda:formKey attribute and in addition + * add all form fields needed for the camunda:formData property. + * + * @class + * @constructor + */ +function MultiCommandHandler(commandStack) { + this._commandStack = commandStack; +} + +MultiCommandHandler.$inject = [ 'commandStack' ]; + +module.exports = MultiCommandHandler; + +MultiCommandHandler.prototype.preExecute = function(context) { + + var commandStack = this._commandStack; + + forEach(context, function(command) { + commandStack.execute(command.cmd, command.context); + }); +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectHandler.js new file mode 100644 index 00000000..0129d6fe --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectHandler.js @@ -0,0 +1,131 @@ +'use strict'; + +var reduce = require('lodash/transform'), + is = require('bpmn-js/lib/util/ModelUtil').is, + keys = require('lodash/keys'), + forEach = require('lodash/forEach'); + +/** + * A handler that implements a BPMN 2.0 property update + * for business objects which are not represented in the + * diagram. + * + * This is useful in the context of the properties panel in + * order to update child elements of elements visible in + * the diagram. + * + * Example: perform an update of a specific event definition + * of an intermediate event. + * + * @class + * @constructor + */ +function UpdateBusinessObjectHandler(elementRegistry) { + this._elementRegistry = elementRegistry; +} + +UpdateBusinessObjectHandler.$inject = [ 'elementRegistry' ]; + +module.exports = UpdateBusinessObjectHandler; + +/** + * returns the root element + */ +function getRoot(businessObject) { + var parent = businessObject; + while (parent.$parent) { + parent = parent.$parent; + } + return parent; +} + +function getProperties(businessObject, propertyNames) { + return reduce(propertyNames, function(result, key) { + result[key] = businessObject.get(key); + return result; + }, {}); +} + + +function setProperties(businessObject, properties) { + forEach(properties, function(value, key) { + businessObject.set(key, value); + }); +} + + +// api ///////////////////////////////////////////// + +/** + * Updates a business object with a list of new properties + * + * @method UpdateBusinessObjectHandler#execute + * + * @param {Object} context + * @param {djs.model.Base} context.element the element which has a child business object updated + * @param {moddle.businessObject} context.businessObject the businessObject to update + * @param {Object} context.properties a list of properties to set on the businessObject + * + * @return {Array} the updated element + */ +UpdateBusinessObjectHandler.prototype.execute = function(context) { + + var element = context.element, + businessObject = context.businessObject, + rootElements = getRoot(businessObject).rootElements, + referenceType = context.referenceType, + referenceProperty = context.referenceProperty, + changed = [ element ]; // this will not change any diagram-js elements + + if (!element) { + throw new Error('element required'); + } + + if (!businessObject) { + throw new Error('businessObject required'); + } + + var properties = context.properties, + oldProperties = context.oldProperties || getProperties(businessObject, keys(properties)); + + // check if there the update needs an external element for reference + if (typeof referenceType !== 'undefined' && typeof referenceProperty !== 'undefined') { + forEach(rootElements, function(rootElement) { + if (is(rootElement, referenceType)) { + if (rootElement.id === properties[referenceProperty]) { + properties[referenceProperty] = rootElement; + } + } + }); + } + + // update properties + setProperties(businessObject, properties); + + // store old values + context.oldProperties = oldProperties; + context.changed = changed; + + // indicate changed on objects affected by the update + return changed; +}; + +/** + * Reverts the update + * + * @method UpdateBusinessObjectHandler#revert + * + * @param {Object} context + * + * @return {djs.mode.Base} the updated element + */ +UpdateBusinessObjectHandler.prototype.revert = function(context) { + + var oldProperties = context.oldProperties, + businessObject = context.businessObject; + + // update properties + setProperties(businessObject, oldProperties); + + return context.changed; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectListHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectListHandler.js new file mode 100644 index 00000000..a86fdc31 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/UpdateBusinessObjectListHandler.js @@ -0,0 +1,115 @@ +'use strict'; + +var forEach = require('lodash/forEach'); + +/** + * A handler that implements a BPMN 2.0 property update + * for business object lists which are not represented in the + * diagram. + * + * This is useful in the context of the properties panel in + * order to update child elements of elements visible in + * the diagram. + * + * Example: perform an update of a specific event definition + * of an intermediate event. + * + * @class + * @constructor + */ +function UpdateBusinessObjectListHandler(elementRegistry, bpmnFactory) { + this._elementRegistry = elementRegistry; + this._bpmnFactory = bpmnFactory; +} + +UpdateBusinessObjectListHandler.$inject = [ 'elementRegistry', 'bpmnFactory' ]; + +module.exports = UpdateBusinessObjectListHandler; + +function ensureNotNull(prop, name) { + if (!prop) { + throw new Error(name + 'required'); + } + return prop; +} + +// api ///////////////////////////////////////////// + +/** + * Updates a element under a provided parent. + */ +UpdateBusinessObjectListHandler.prototype.execute = function(context) { + + var currentObject = ensureNotNull(context.currentObject, 'currentObject'), + propertyName = ensureNotNull(context.propertyName, 'propertyName'), + updatedObjectList = context.updatedObjectList, + objectsToRemove = context.objectsToRemove || [], + objectsToAdd = context.objectsToAdd || [], + changed = [ context.element], // this will not change any diagram-js elements + referencePropertyName; + + if (context.referencePropertyName) { + referencePropertyName = context.referencePropertyName; + } + + var objectList = currentObject[propertyName]; + // adjust array reference in the parent business object + context.previousList = currentObject[propertyName]; + + if (updatedObjectList) { + currentObject[propertyName] = updatedObjectList; + } else { + var listCopy = []; + // remove all objects which should be removed + forEach(objectList, function(object) { + if (objectsToRemove.indexOf(object) == -1) { + listCopy.push(object); + } + }); + // add all objects which should be added + listCopy = listCopy.concat(objectsToAdd); + + // set property to new list + if (listCopy.length > 0 || !referencePropertyName) { + + // as long as there are elements in the list update the list + currentObject[propertyName] = listCopy; + } else if (referencePropertyName) { + + // remove the list when it is empty + var parentObject = currentObject.$parent; + parentObject.set(referencePropertyName, undefined); + } + } + + context.changed = changed; + + // indicate changed on objects affected by the update + return changed; +}; + +/** + * Reverts the update + * + * @method CreateBusinessObjectListHandler#revert + * + * @param {Object} context + * + * @return {djs.mode.Base} the updated element + */ +UpdateBusinessObjectListHandler.prototype.revert = function(context) { + + var currentObject = context.currentObject, + propertyName = context.propertyName, + previousList = context.previousList, + parentObject = currentObject.$parent; + + if (context.referencePropertyName) { + parentObject.set(context.referencePropertyName, currentObject); + } + + // remove new element + currentObject.set(propertyName, previousList); + + return context.changed; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/index.js new file mode 100644 index 00000000..f60cf22c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/cmd/index.js @@ -0,0 +1,27 @@ +'use strict'; + +var forEach = require('lodash/forEach'); + +var HANDLERS = { + 'properties-panel.update-businessobject': require('./UpdateBusinessObjectHandler'), + 'properties-panel.create-and-reference': require('./CreateAndReferenceHandler'), + 'properties-panel.create-businessobject-list': require('./CreateBusinessObjectListHandler'), + 'properties-panel.update-businessobject-list': require('./UpdateBusinessObjectListHandler'), + 'properties-panel.multi-command-executor': require('./MultiCommandHandler') +}; + + +function CommandInitializer(eventBus, commandStack) { + + eventBus.on('diagram.init', function() { + forEach(HANDLERS, function(handler, id) { + commandStack.registerHandler(id, handler); + }); + }); +} + +CommandInitializer.$inject = [ 'eventBus', 'commandStack' ]; + +module.exports = { + __init__: [ CommandInitializer ] +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/CheckboxEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/CheckboxEntryFactory.js new file mode 100644 index 00000000..b588bfcf --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/CheckboxEntryFactory.js @@ -0,0 +1,77 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + cmdHelper = require('../helper/CmdHelper'), + escapeHTML = require('../Utils').escapeHTML; + +var entryFieldDescription = require('./EntryFieldDescription'); + + +var checkbox = function(options, defaultParameters) { + var resource = defaultParameters, + id = resource.id, + label = options.label || id, + canBeDisabled = !!options.disabled && typeof options.disabled === 'function', + canBeHidden = !!options.hidden && typeof options.hidden === 'function', + description = options.description; + + resource.html = + '' + + '' + escapeHTML(label) + ''; + + // add description below checkbox entry field + if (description) { + resource.html += entryFieldDescription(description); + } + + resource.get = function(element) { + var bo = getBusinessObject(element), + res = {}; + + res[options.modelProperty] = bo.get(options.modelProperty); + + return res; + }; + + resource.set = function(element, values) { + var res = {}; + + res[options.modelProperty] = !!values[options.modelProperty]; + + return cmdHelper.updateProperties(element, res); + }; + + if (typeof options.set === 'function') { + resource.set = options.set; + } + + if (typeof options.get === 'function') { + resource.get = options.get; + } + + if (canBeDisabled) { + resource.isDisabled = function() { + return options.disabled.apply(resource, arguments); + }; + } + + if (canBeHidden) { + resource.isHidden = function() { + return !options.hidden.apply(resource, arguments); + }; + } + + resource.cssClasses = ['bpp-checkbox']; + + return resource; +}; + +module.exports = checkbox; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ComboEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ComboEntryFactory.js new file mode 100644 index 00000000..77a69aea --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ComboEntryFactory.js @@ -0,0 +1,118 @@ +'use strict'; + +var assign = require('lodash/assign'), + find = require('lodash/find'); + +var domQuery = require('min-dom').query; + +var escapeHTML = require('../Utils').escapeHTML; + +var selectEntryFactory = require('./SelectEntryFactory'), + entryFieldDescription = require('./EntryFieldDescription'); + + +/** + * The combo box is a special implementation of the select entry and adds the option 'custom' to the + * select box. If 'custom' is selected, an additional text input field is shown which allows to define + * a custom value. + * + * @param {Object} options + * @param {string} options.id + * @param {string} options.label + * @param {Array} options.selectOptions list of name/value pairs + * @param {string} options.modelProperty + * @param {function} options.get + * @param {function} options.set + * @param {string} [options.customValue] custom select option value (default: 'custom') + * @param {string} [options.customName] custom select option name visible in the select box (default: 'custom') + * + * @return {Object} + */ +var comboBox = function(options) { + + var selectOptions = options.selectOptions, + modelProperty = options.modelProperty, + customValue = options.customValue || 'custom', + customName = options.customName || 'custom ' + modelProperty, + description = options.description; + + // check if a value is not a built in value + var isCustomValue = function(value) { + if (typeof value[modelProperty] === 'undefined') { + return false; + } + + var isCustom = !find(selectOptions, function(option) { + return value[modelProperty] === option.value; + }); + + return isCustom; + }; + + var comboOptions = assign({}, options); + + // true if the selected value in the select box is customValue + comboOptions.showCustomInput = function(element, node) { + var selectBox = domQuery('[data-entry="'+ options.id +'"] select', node.parentNode); + + if (selectBox) { + return selectBox.value === customValue; + } + + return false; + }; + + comboOptions.get = function(element, node) { + var value = options.get(element, node); + + var modifiedValues = {}; + + if (!isCustomValue(value)) { + modifiedValues[modelProperty] = value[modelProperty] || ''; + + return modifiedValues; + } + + modifiedValues[modelProperty] = customValue; + modifiedValues['custom-'+modelProperty] = value[modelProperty]; + + return modifiedValues; + }; + + comboOptions.set = function(element, values, node) { + var modifiedValues = {}; + + // if the custom select option has been selected + // take the value from the text input field + if (values[modelProperty] === customValue) { + modifiedValues[modelProperty] = values['custom-' + modelProperty] || ''; + } + else if (options.emptyParameter && values[modelProperty] === '') { + modifiedValues[modelProperty] = undefined; + } else { + modifiedValues[modelProperty] = values[modelProperty]; + } + return options.set(element, modifiedValues, node); + }; + + comboOptions.selectOptions.push({ name: customName, value: customValue }); + + var comboBoxEntry = assign({}, selectEntryFactory(comboOptions, comboOptions)); + + comboBoxEntry.html += '' + + '' + + ''; + + // add description below combo box entry field + if (description) { + comboBoxEntry.html += entryFieldDescription(description); + } + + return comboBoxEntry; +}; + +module.exports = comboBox; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFactory.js new file mode 100644 index 00000000..4e4104d5 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFactory.js @@ -0,0 +1,163 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +// input entities +var textInputField = require('./TextInputEntryFactory'), + checkboxField = require('./CheckboxEntryFactory'), + selectBoxField = require('./SelectEntryFactory'), + comboBoxField = require('./ComboEntryFactory'), + textBoxField = require('./TextBoxEntryFactory'), + validationAwareTextInputField = require('./ValidationAwareTextInput'), + tableField = require('./TableEntryFactory'), + labelEntry = require('./LabelFactory'), + link = require('./LinkEntryFactory'); + +var cmdHelper = require('../helper/CmdHelper'); + +// helpers //////////////////////////////////////// + +function ensureNotNull(prop) { + if (!prop) { + throw new Error(prop + ' must be set.'); + } + + return prop; +} + +/** + * sets the default parameters which are needed to create an entry + * + * @param options + * @returns {{id: *, description: (*|string), get: (*|Function), set: (*|Function), + * validate: (*|Function), html: string}} + */ +var setDefaultParameters = function(options) { + + // default method to fetch the current value of the input field + var defaultGet = function(element) { + var bo = getBusinessObject(element), + res = {}, + prop = ensureNotNull(options.modelProperty); + res[prop] = bo.get(prop); + + return res; + }; + + // default method to set a new value to the input field + var defaultSet = function(element, values) { + var res = {}, + prop = ensureNotNull(options.modelProperty); + if (values[prop] !== '') { + res[prop] = values[prop]; + } else { + res[prop] = undefined; + } + + return cmdHelper.updateProperties(element, res); + }; + + // default validation method + var defaultValidate = function() { + return {}; + }; + + return { + id : options.id, + description : (options.description || ''), + get : (options.get || defaultGet), + set : (options.set || defaultSet), + validate : (options.validate || defaultValidate), + html: '' + }; +}; + +function EntryFactory() { + +} + +/** + * Generates an text input entry object for a property panel. + * options are: + * - id: id of the entry - String + * + * - description: description of the property - String + * + * - label: label for the input field - String + * + * - set: setter method - Function + * + * - get: getter method - Function + * + * - validate: validation mehtod - Function + * + * - modelProperty: name of the model property - String + * + * - buttonAction: Object which contains the following properties: - Object + * ---- name: name of the [data-action] callback - String + * ---- method: callback function for [data-action] - Function + * + * - buttonShow: Object which contains the following properties: - Object + * ---- name: name of the [data-show] callback - String + * ---- method: callback function for [data-show] - Function + * + * @param options + * @returns the propertyPanel entry resource object + */ +EntryFactory.textField = function(options) { + return textInputField(options, setDefaultParameters(options)); +}; + +EntryFactory.validationAwareTextField = function(options) { + return validationAwareTextInputField(options, setDefaultParameters(options)); +}; + +/** + * Generates a checkbox input entry object for a property panel. + * options are: + * - id: id of the entry - String + * + * - description: description of the property - String + * + * - label: label for the input field - String + * + * - set: setter method - Function + * + * - get: getter method - Function + * + * - validate: validation method - Function + * + * - modelProperty: name of the model property - String + * + * @param options + * @returns the propertyPanel entry resource object + */ +EntryFactory.checkbox = function(options) { + return checkboxField(options, setDefaultParameters(options)); +}; + +EntryFactory.textBox = function(options) { + return textBoxField(options, setDefaultParameters(options)); +}; + +EntryFactory.selectBox = function(options) { + return selectBoxField(options, setDefaultParameters(options)); +}; + +EntryFactory.comboBox = function(options) { + return comboBoxField(options); +}; + +EntryFactory.table = function(options) { + return tableField(options); +}; + +EntryFactory.label = function(options) { + return labelEntry(options); +}; + +EntryFactory.link = function(options) { + return link(options); +}; + +module.exports = EntryFactory; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFieldDescription.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFieldDescription.js new file mode 100644 index 00000000..48f6dcfb --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/EntryFieldDescription.js @@ -0,0 +1,49 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +/** + * Create a linkified and HTML escaped entry field description. + * + * As a special feature, this description may contain both markdown + * and plain links. + * + * @param {String} description + */ +module.exports = function entryFieldDescription(description) { + + // we tokenize the description to extract text, HTML and markdown links + // text and links are handled seperately + + var escaped = []; + + // match markdown [{TEXT}]({URL}) and HTML links {TEXT} + var pattern = /(?:\[([^\]]+)\]\((https?:\/\/[^"<>\]]+)\))|(?:]+)">([^<]*)<\/a>)/gi; + + var index = 0; + var match; + var link, text; + + while ((match = pattern.exec(description))) { + + // escape + insert text before match + if (match.index > index) { + escaped.push(escapeHTML(description.substring(index, match.index))); + } + + link = match[2] || match[3]; + text = match[1] || match[4]; + + // insert safe link + escaped.push('' + escapeHTML(text) + ''); + + index = match.index + match[0].length; + } + + // escape and insert text after last match + if (index < description.length) { + escaped.push(escapeHTML(description.substring(index))); + } + + return '' + escaped.join('') + ''; +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LabelFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LabelFactory.js new file mode 100644 index 00000000..3c8bdbfc --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LabelFactory.js @@ -0,0 +1,38 @@ +'use strict'; + +/** + * The label factory provides a label entry. For the label text + * it expects either a string provided by the options.labelText + * parameter or it could be generated programmatically using a + * function passed as the options.get parameter. + * + * @param {Object} options + * @param {string} options.id + * @param {string} [options.labelText] + * @param {Function} [options.get] + * @param {Function} [options.showLabel] + * @param {Boolean} [options.divider] adds a divider at the top of the label if true; default: false + */ +var label = function(options) { + return { + id: options.id, + html: '' + + '', + get: function(element, node) { + if (typeof options.get === 'function') { + return options.get(element, node); + } + return { label: options.labelText }; + }, + showLabel: function(element, node) { + if (typeof options.showLabel === 'function') { + return options.showLabel(element, node); + } + return true; + } + }; +}; + +module.exports = label; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LinkEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LinkEntryFactory.js new file mode 100644 index 00000000..d04691d2 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/LinkEntryFactory.js @@ -0,0 +1,78 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +var entryFieldDescription = require('./EntryFieldDescription'); + +var bind = require('lodash/bind'); + +/** + * An entry that renders a clickable link. + * + * A passed {@link options#handleClick} handler is responsible + * to process the click. + * + * The link may be conditionally shown or hidden. This can be + * controlled via the {@link options.showLink}. + * + * @param {Object} options + * @param {String} options.id + * @param {String} [options.label] + * @param {Function} options.handleClick + * @param {Function} [options.showLink] returning false to hide link + * @param {String} [options.description] + * + * @example + * + * var linkEntry = link({ + * id: 'foo', + * description: 'Some Description', + * handleClick: function(element, node, event) { ... }, + * showLink: function(element, node) { ... } + * }); + * + * @return {Entry} the newly created entry + */ +function link(options) { + + var id = options.id, + label = options.label || id, + showLink = options.showLink, + handleClick = options.handleClick, + description = options.description; + + if (showLink && typeof showLink !== 'function') { + throw new Error('options.showLink must be a function'); + } + + if (typeof handleClick !== 'function') { + throw new Error('options.handleClick must be a function'); + } + + var resource = { + id: id + }; + + resource.html = + '' + escapeHTML(label) + ''; + + // add description below link entry field + if (description) { + resource.html += entryFieldDescription(description); + } + + resource.handleClick = bind(handleClick, resource); + + if (typeof showLink === 'function') { + resource.showLink = function() { + return showLink.apply(resource, arguments); + }; + } + + return resource; +} + +module.exports = link; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/SelectEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/SelectEntryFactory.js new file mode 100644 index 00000000..3a78a166 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/SelectEntryFactory.js @@ -0,0 +1,137 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +var domify = require('min-dom').domify; + +var forEach = require('lodash/forEach'); + +var entryFieldDescription = require('./EntryFieldDescription'); + + +var isList = function(list) { + return !(!list || Object.prototype.toString.call(list) !== '[object Array]'); +}; + +var addEmptyParameter = function(list) { + return list.concat([ { name: '', value: '' } ]); +}; + +var createOption = function(option) { + return '' + option.name + ''; +}; + +/** + * @param {Object} options + * @param {string} options.id + * @param {string} [options.label] + * @param {Array} options.selectOptions + * @param {string} options.modelProperty + * @param {boolean} options.emptyParameter + * @param {function} options.disabled + * @param {function} options.hidden + * @param {Object} defaultParameters + * + * @return {Object} + */ +var selectbox = function(options, defaultParameters) { + var resource = defaultParameters, + label = options.label || resource.id, + selectOptions = options.selectOptions || [ { name: '', value: '' } ], + modelProperty = options.modelProperty, + emptyParameter = options.emptyParameter, + canBeDisabled = !!options.disabled && typeof options.disabled === 'function', + canBeHidden = !!options.hidden && typeof options.hidden === 'function', + description = options.description; + + + if (emptyParameter) { + selectOptions = addEmptyParameter(selectOptions); + } + + + resource.html = + '' + escapeHTML(label) + '' + + ''; + + if (isList(selectOptions)) { + forEach(selectOptions, function(option) { + resource.html += '' + + (option.name ? escapeHTML(option.name) : '') + ''; + }); + } + + resource.html += ''; + + // add description below select box entry field + if (description && typeof options.showCustomInput !== 'function') { + resource.html += entryFieldDescription(description); + } + + /** + * Fill the select box options dynamically. + * + * Calls the defined function #selectOptions in the entry to get the + * values for the options and set the value to the inputNode. + * + * @param {djs.model.Base} element + * @param {HTMLElement} entryNode + * @param {EntryDescriptor} inputNode + * @param {Object} inputName + * @param {Object} newValue + */ + resource.setControlValue = function(element, entryNode, inputNode, inputName, newValue) { + if (typeof selectOptions === 'function') { + + var options = selectOptions(element, inputNode); + + if (options) { + + // remove existing options + while (inputNode.firstChild) { + inputNode.removeChild(inputNode.firstChild); + } + + // add options + forEach(options, function(option) { + var template = domify(createOption(option)); + + inputNode.appendChild(template); + }); + + + } + } + + // set select value + if (newValue !== undefined) { + inputNode.value = newValue; + } + + }; + + if (canBeDisabled) { + resource.isDisabled = function() { + return options.disabled.apply(resource, arguments); + }; + } + + if (canBeHidden) { + resource.isHidden = function() { + return !options.hidden.apply(resource, arguments); + }; + } + + resource.cssClasses = ['bpp-dropdown']; + + return resource; +}; + +module.exports = selectbox; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TableEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TableEntryFactory.js new file mode 100644 index 00000000..5b8696c1 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TableEntryFactory.js @@ -0,0 +1,338 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +var cmdHelper = require('../helper/CmdHelper'); + +var domQuery = require('min-dom').query, + domAttr = require('min-dom').attr, + domClosest = require('min-dom').closest; + +var filter = require('lodash/filter'), + forEach = require('lodash/forEach'), + keys = require('lodash/keys'); + +var domify = require('min-dom').domify; + +var entryFieldDescription = require('./EntryFieldDescription'); + +var updateSelection = require('selection-update'); + +var TABLE_ROW_DIV_SNIPPET = ''; +var DELETE_ROW_BUTTON_SNIPPET = '' + + 'X' + + ''; + +function createInputRowTemplate(properties, canRemove) { + var template = TABLE_ROW_DIV_SNIPPET; + template += createInputTemplate(properties, canRemove); + template += canRemove ? DELETE_ROW_BUTTON_SNIPPET : ''; + template += ''; + + return template; +} + +function createInputTemplate(properties, canRemove) { + var columns = properties.length; + var template = ''; + forEach(properties, function(prop) { + template += ''; + }); + return template; +} + +function createLabelRowTemplate(labels) { + var template = TABLE_ROW_DIV_SNIPPET; + template += createLabelTemplate(labels); + template += ''; + + return template; +} + +function createLabelTemplate(labels) { + var columns = labels.length; + var template = ''; + forEach(labels, function(label) { + template += '' + escapeHTML(label) + ''; + }); + return template; +} + +function pick(elements, properties) { + return (elements || []).map(function(elem) { + var newElement = {}; + forEach(properties, function(prop) { + newElement[prop] = elem[prop] || ''; + }); + return newElement; + }); +} + +function diff(element, node, values, oldValues, editable) { + return filter(values, function(value, idx) { + return !valueEqual(element, node, value, oldValues[idx], editable, idx); + }); +} + +function valueEqual(element, node, value, oldValue, editable, idx) { + if (value && !oldValue) { + return false; + } + var allKeys = keys(value).concat(keys(oldValue)); + + return allKeys.every(function(key) { + var n = value[key] || undefined; + var o = oldValue[key] || undefined; + return !editable(element, node, key, idx) || n === o; + }); +} + +function getEntryNode(node) { + return domClosest(node, '[data-entry]', true); +} + +function getContainer(node) { + return domQuery('div[data-list-entry-container]', node); +} + +function getSelection(node) { + return { + start: node.selectionStart, + end: node.selectionEnd + }; +} + +function setSelection(node, selection) { + node.selectionStart = selection.start; + node.selectionEnd = selection.end; +} + +/** + * @param {Object} options + * @param {string} options.id + * @param {string} options.description + * @param {Array} options.modelProperties + * @param {Array} options.labels + * @param {Function} options.getElements - this callback function must return a list of business object items + * @param {Function} options.removeElement + * @param {Function} options.addElement + * @param {Function} options.updateElement + * @param {Function} options.editable + * @param {Function} options.setControlValue + * @param {Function} options.show + * + * @return {Object} + */ +module.exports = function(options) { + + var id = options.id, + modelProperties = options.modelProperties, + labels = options.labels, + description = options.description; + + var labelRow = createLabelRowTemplate(labels); + + var getElements = options.getElements; + + var removeElement = options.removeElement, + canRemove = typeof removeElement === 'function'; + + var addElement = options.addElement, + canAdd = typeof addElement === 'function', + addLabel = options.addLabel || 'Add Value'; + + var updateElement = options.updateElement, + canUpdate = typeof updateElement === 'function'; + + var editable = options.editable || function() { return true; }, + setControlValue = options.setControlValue; + + var show = options.show, + canBeShown = typeof show === 'function'; + + var elements = function(element, node) { + return pick(getElements(element, node), modelProperties); + }; + + var factory = { + id: id, + html: (canAdd ? + '' + + '' + escapeHTML(addLabel) + '' + + '+' + + '' : '') + + '' + + '' + + labelRow + + '' + + '' + + '' + + '' + + + // add description below table entry field + (description ? entryFieldDescription(description) : ''), + + get: function(element, node) { + var boElements = elements(element, node, this.__invalidValues); + + var invalidValues = this.__invalidValues; + + delete this.__invalidValues; + + forEach(invalidValues, function(value, idx) { + var element = boElements[idx]; + + forEach(modelProperties, function(prop) { + element[prop] = value[prop]; + }); + }); + + return boElements; + }, + + set: function(element, values, node) { + var action = this.__action || {}; + delete this.__action; + + if (action.id === 'delete-element') { + return removeElement(element, node, action.idx); + } + else if (action.id === 'add-element') { + return addElement(element, node); + } + else if (canUpdate) { + var commands = [], + valuesToValidate = values; + + if (typeof options.validate !== 'function') { + valuesToValidate = diff(element, node, values, elements(element, node), editable); + } + + var self = this; + + forEach(valuesToValidate, function(value) { + var validationError, + idx = values.indexOf(value); + + if (typeof options.validate === 'function') { + validationError = options.validate(element, value, node, idx); + } + + if (!validationError) { + var cmd = updateElement(element, value, node, idx); + + if (cmd) { + commands.push(cmd); + } + } else { + // cache invalid value in an object by index as key + self.__invalidValues = self.__invalidValues || {}; + self.__invalidValues[idx] = value; + + // execute a command, which does not do anything + commands.push(cmdHelper.updateProperties(element, {})); + } + }); + + return commands; + } + }, + createListEntryTemplate: function(value, index, selectBox) { + return createInputRowTemplate(modelProperties, canRemove); + }, + + addElement: function(element, node, event, scopeNode) { + var template = domify(createInputRowTemplate(modelProperties, canRemove)); + + var container = getContainer(node); + container.appendChild(template); + + this.__action = { + id: 'add-element' + }; + + return true; + }, + + deleteElement: function(element, node, event, scopeNode) { + var container = getContainer(node); + var rowToDelete = event.delegateTarget.parentNode; + var idx = parseInt(domAttr(rowToDelete, 'data-index'), 10); + + container.removeChild(rowToDelete); + + this.__action = { + id: 'delete-element', + idx: idx + }; + + return true; + }, + + editable: function(element, rowNode, input, prop, value, idx) { + var entryNode = domClosest(rowNode, '[data-entry]'); + return editable(element, entryNode, prop, idx); + }, + + show: function(element, entryNode, node, scopeNode) { + entryNode = getEntryNode(entryNode); + return show(element, entryNode, node, scopeNode); + }, + + showTable: function(element, entryNode, node, scopeNode) { + entryNode = getEntryNode(entryNode); + var elems = elements(element, entryNode); + return elems && elems.length && (!canBeShown || show(element, entryNode, node, scopeNode)); + }, + + validateListItem: function(element, value, node, idx) { + if (typeof options.validate === 'function') { + return options.validate(element, value, node, idx); + } + } + + }; + + // Update/set the selection on the correct position. + // It's the same code like for an input value in the PropertiesPanel.js. + if (setControlValue) { + factory.setControlValue = function(element, rowNode, input, prop, value, idx) { + var entryNode = getEntryNode(rowNode); + + var isReadOnly = domAttr(input, 'readonly'); + var oldValue = input.value; + + var selection; + + // prevents input fields from having the value 'undefined' + if (value === undefined) { + value = ''; + } + + // when the attribute 'readonly' exists, ignore the comparison + // with 'oldValue' and 'value' + if (!!isReadOnly && oldValue === value) { + return; + } + + // update selection on undo/redo + if (document.activeElement === input) { + selection = updateSelection(getSelection(input), oldValue, value); + } + + setControlValue(element, entryNode, input, prop, value, idx); + + if (selection) { + setSelection(input, selection); + } + + }; + } + + return factory; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextBoxEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextBoxEntryFactory.js new file mode 100644 index 00000000..25e7f6b8 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextBoxEntryFactory.js @@ -0,0 +1,42 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +var entryFieldDescription = require('./EntryFieldDescription'); + + +var textBox = function(options, defaultParameters) { + + var resource = defaultParameters, + label = options.label || resource.id, + canBeShown = !!options.show && typeof options.show === 'function', + description = options.description; + + resource.html = + '' + label + '' + + '' + + '' + + ''; + + // add description below text box entry field + if (description) { + resource.html += entryFieldDescription(description); + } + + if (canBeShown) { + resource.isShown = function() { + return options.show.apply(resource, arguments); + }; + } + + resource.cssClasses = ['bpp-textbox']; + + return resource; +}; + +module.exports = textBox; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextInputEntryFactory.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextInputEntryFactory.js new file mode 100644 index 00000000..6b0736d5 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/TextInputEntryFactory.js @@ -0,0 +1,85 @@ +'use strict'; + +var escapeHTML = require('../Utils').escapeHTML; + +var domQuery = require('min-dom').query; + +var entryFieldDescription = require('./EntryFieldDescription'); + + +var textField = function(options, defaultParameters) { + + // Default action for the button next to the input-field + var defaultButtonAction = function(element, inputNode) { + var input = domQuery('input[name="' + options.modelProperty + '"]', inputNode); + input.value = ''; + + return true; + }; + + // default method to determine if the button should be visible + var defaultButtonShow = function(element, inputNode) { + var input = domQuery('input[name="' + options.modelProperty + '"]', inputNode); + + return input.value !== ''; + }; + + + var resource = defaultParameters, + label = options.label || resource.id, + dataValueLabel = options.dataValueLabel, + buttonLabel = (options.buttonLabel || 'X'), + actionName = (typeof options.buttonAction != 'undefined') ? options.buttonAction.name : 'clear', + actionMethod = (typeof options.buttonAction != 'undefined') ? options.buttonAction.method : defaultButtonAction, + showName = (typeof options.buttonShow != 'undefined') ? options.buttonShow.name : 'canClear', + showMethod = (typeof options.buttonShow != 'undefined') ? options.buttonShow.method : defaultButtonShow, + canBeDisabled = !!options.disabled && typeof options.disabled === 'function', + canBeHidden = !!options.hidden && typeof options.hidden === 'function', + description = options.description; + + resource.html = + ''+ escapeHTML(label) +'' + + '' + + '' + + '' + + '' + escapeHTML(buttonLabel) + '' + + '' + + ''; + + // add description below text input entry field + if (description) { + resource.html += entryFieldDescription(description); + } + + resource[actionName] = actionMethod; + resource[showName] = showMethod; + + if (canBeDisabled) { + resource.isDisabled = function() { + return options.disabled.apply(resource, arguments); + }; + } + + if (canBeHidden) { + resource.isHidden = function() { + return !options.hidden.apply(resource, arguments); + }; + } + + resource.cssClasses = ['bpp-textfield']; + + return resource; +}; + +module.exports = textField; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ValidationAwareTextInput.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ValidationAwareTextInput.js new file mode 100644 index 00000000..dd82c03b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/factory/ValidationAwareTextInput.js @@ -0,0 +1,56 @@ +'use strict'; + +var textField = require('./TextInputEntryFactory'); + +/** + * This function is a wrapper around TextInputEntryFactory. + * It adds functionality to cache an invalid value entered in the + * text input, instead of setting it on the business object. + */ +var validationAwareTextField = function(options, defaultParameters) { + + var modelProperty = options.modelProperty; + + defaultParameters.get = function(element, node) { + var value = this.__lastInvalidValue; + + delete this.__lastInvalidValue; + + var properties = {}; + + properties[modelProperty] = value !== undefined ? value : options.getProperty(element, node); + + return properties; + }; + + defaultParameters.set = function(element, values, node) { + var validationErrors = validate.apply(this, [ element, values, node ]), + propertyValue = values[modelProperty]; + + // make sure we do not update the id + if (validationErrors && validationErrors[modelProperty]) { + this.__lastInvalidValue = propertyValue; + + return options.setProperty(element, {}, node); + } else { + var properties = {}; + + properties[modelProperty] = propertyValue; + + return options.setProperty(element, properties, node); + } + }; + + var validate = defaultParameters.validate = function(element, values, node) { + var value = values[modelProperty] || this.__lastInvalidValue; + + var property = {}; + property[modelProperty] = value; + + return options.validate(element, property, node); + }; + + return textField(options, defaultParameters); +}; + +module.exports = validationAwareTextField; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/AsyncCapableHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/AsyncCapableHelper.js new file mode 100644 index 00000000..e238941d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/AsyncCapableHelper.js @@ -0,0 +1,76 @@ +'use strict'; + +var map = require('lodash/map'); + +var extensionElementsHelper = require('./ExtensionElementsHelper'); + +/** + * Returns true if the attribute 'activiti:asyncBefore' is set + * to true. + * + * @param {ModdleElement} bo + * + * @return {boolean} a boolean value + */ +function isAsyncBefore(bo) { + return !!(bo.get('activiti:asyncBefore') || bo.get('activiti:async')); +} + +module.exports.isAsyncBefore = isAsyncBefore; + +/** + * Returns true if the attribute 'activiti:asyncAfter' is set + * to true. + * + * @param {ModdleElement} bo + * + * @return {boolean} a boolean value + */ +function isAsyncAfter(bo) { + return !!bo.get('activiti:asyncAfter'); +} + +module.exports.isAsyncAfter = isAsyncAfter; + +/** + * Returns true if the attribute 'activiti:exclusive' is set + * to true. + * + * @param {ModdleElement} bo + * + * @return {boolean} a boolean value + */ +function isExclusive(bo) { + return !!bo.get('activiti:exclusive'); +} + +module.exports.isExclusive = isExclusive; + +/** + * Get first 'activiti:FailedJobRetryTimeCycle' from the business object. + * + * @param {ModdleElement} bo + * + * @return {Array} a list of 'activiti:FailedJobRetryTimeCycle' + */ +function getFailedJobRetryTimeCycle(bo) { + return (extensionElementsHelper.getExtensionElements(bo, 'activiti:FailedJobRetryTimeCycle') || [])[0]; +} + +module.exports.getFailedJobRetryTimeCycle = getFailedJobRetryTimeCycle; + +/** + * Removes all existing 'activiti:FailedJobRetryTimeCycle' from the business object + * + * @param {ModdleElement} bo + * + * @return {Array} a list of 'activiti:FailedJobRetryTimeCycle' + */ +function removeFailedJobRetryTimeCycle(bo, element) { + var retryTimeCycles = extensionElementsHelper.getExtensionElements(bo, 'activiti:FailedJobRetryTimeCycle'); + return map(retryTimeCycles, function(cycle) { + return extensionElementsHelper.removeEntry(bo, element, cycle); + }); +} + +module.exports.removeFailedJobRetryTimeCycle = removeFailedJobRetryTimeCycle; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CategoryHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CategoryHelper.js new file mode 100644 index 00000000..04390d9c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CategoryHelper.js @@ -0,0 +1,31 @@ +'use strict'; + +var collectionAdd = require('diagram-js/lib/util/Collections').add, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var CategoryHelper = {}; + +module.exports = CategoryHelper; + +/** + * Creates a new bpmn:CategoryValue inside a new bpmn:Category + * + * @param {ModdleElement} definitions + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} categoryValue. + */ +CategoryHelper.createCategoryValue = function(definitions, bpmnFactory) { + var categoryValue = bpmnFactory.create('bpmn:CategoryValue'), + category = bpmnFactory.create('bpmn:Category', { + categoryValue: [ categoryValue ] + }); + + // add to correct place + collectionAdd(definitions.get('rootElements'), category); + getBusinessObject(category).$parent = definitions; + getBusinessObject(categoryValue).$parent = category; + + return categoryValue; + +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CmdHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CmdHelper.js new file mode 100644 index 00000000..dd58b067 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/CmdHelper.js @@ -0,0 +1,77 @@ +'use strict'; + +var CmdHelper = {}; +module.exports = CmdHelper; + +CmdHelper.updateProperties = function(element, properties) { + return { + cmd: 'element.updateProperties', + context: { element: element, properties: properties } + }; +}; + +CmdHelper.updateBusinessObject = function(element, businessObject, newProperties) { + return { + cmd: 'properties-panel.update-businessobject', + context: { + element: element, + businessObject: businessObject, + properties: newProperties + } + }; +}; + +CmdHelper.addElementsTolist = function(element, businessObject, listPropertyName, objectsToAdd) { + return { + cmd: 'properties-panel.update-businessobject-list', + context: { + element: element, + currentObject: businessObject, + propertyName: listPropertyName, + objectsToAdd: objectsToAdd + } + }; +}; + +CmdHelper.removeElementsFromList = function(element, businessObject, listPropertyName, referencePropertyName, objectsToRemove) { + + return { + cmd: 'properties-panel.update-businessobject-list', + context: { + element: element, + currentObject: businessObject, + propertyName: listPropertyName, + referencePropertyName: referencePropertyName, + objectsToRemove: objectsToRemove + } + }; +}; + + +CmdHelper.addAndRemoveElementsFromList = function(element, businessObject, listPropertyName, referencePropertyName, objectsToAdd, objectsToRemove) { + + return { + cmd: 'properties-panel.update-businessobject-list', + context: { + element: element, + currentObject: businessObject, + propertyName: listPropertyName, + referencePropertyName: referencePropertyName, + objectsToAdd: objectsToAdd, + objectsToRemove: objectsToRemove + } + }; +}; + + +CmdHelper.setList = function(element, businessObject, listPropertyName, updatedObjectList) { + return { + cmd: 'properties-panel.update-businessobject-list', + context: { + element: element, + currentObject: businessObject, + propertyName: listPropertyName, + updatedObjectList: updatedObjectList + } + }; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ElementHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ElementHelper.js new file mode 100644 index 00000000..b4320ade --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ElementHelper.js @@ -0,0 +1,23 @@ +'use strict'; + +var ElementHelper = {}; +module.exports = ElementHelper; + +/** + * Creates a new element and set the parent to it + * + * @method ElementHelper#createElement + * + * @param {String} elementType of the new element + * @param {Object} properties of the new element in key-value pairs + * @param {moddle.object} parent of the new element + * @param {BpmnFactory} factory which creates the new element + * + * @returns {djs.model.Base} element which is created + */ +ElementHelper.createElement = function(elementType, properties, parent, factory) { + var element = factory.create(elementType, properties); + element.$parent = parent; + + return element; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/EventDefinitionHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/EventDefinitionHelper.js new file mode 100644 index 00000000..d4c74baa --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/EventDefinitionHelper.js @@ -0,0 +1,57 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is, + forEach = require('lodash/forEach'); + +var EventDefinitionHelper = {}; + +module.exports = EventDefinitionHelper; + +EventDefinitionHelper.getEventDefinition = function(element, eventType) { + + var bo = getBusinessObject(element), + eventDefinition = null; + + if (bo.eventDefinitions) { + forEach(bo.eventDefinitions, function(event) { + if (is(event, eventType)) { + eventDefinition = event; + } + }); + } + + return eventDefinition; +}; + +EventDefinitionHelper.getTimerEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:TimerEventDefinition'); +}; + +EventDefinitionHelper.getMessageEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:MessageEventDefinition'); +}; + +EventDefinitionHelper.getSignalEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:SignalEventDefinition'); +}; + +EventDefinitionHelper.getErrorEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:ErrorEventDefinition'); +}; + +EventDefinitionHelper.getEscalationEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:EscalationEventDefinition'); +}; + +EventDefinitionHelper.getCompensateEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:CompensateEventDefinition'); +}; + +EventDefinitionHelper.getLinkEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:LinkEventDefinition'); +}; + +EventDefinitionHelper.getConditionalEventDefinition = function(element) { + return this.getEventDefinition(element, 'bpmn:ConditionalEventDefinition'); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ExtensionElementsHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ExtensionElementsHelper.js new file mode 100644 index 00000000..59eb2811 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ExtensionElementsHelper.js @@ -0,0 +1,54 @@ +'use strict'; + +var cmdHelper = require('./CmdHelper'), + elementHelper = require('./ElementHelper'); + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var ExtensionElementsHelper = {}; + +var getExtensionElements = function(bo) { + return bo.get('extensionElements'); +}; + +ExtensionElementsHelper.getExtensionElements = function(bo, type) { + var extensionElements = getExtensionElements(bo); + if (typeof extensionElements !== 'undefined') { + var extensionValues = extensionElements.get('values'); + if (typeof extensionValues !== 'undefined') { + var elements = extensionValues.filter(function(value) { + return is(value, type); + }); + if (elements.length) { + return elements; + } + } + } +}; + +ExtensionElementsHelper.addEntry = function(bo, element, entry, bpmnFactory) { + var extensionElements = bo.get('extensionElements'); + + // if there is no extensionElements list, create one + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [entry] }, bo, bpmnFactory); + return { extensionElements : extensionElements }; + } else { + // add new failedJobRetryExtensionElement to existing extensionElements list + return cmdHelper.addElementsTolist(element, extensionElements, 'values', [entry]); + } +}; + +ExtensionElementsHelper.removeEntry = function(bo, element, entry) { + var extensionElements = bo.get('extensionElements'); + + if (!extensionElements) { + + // return an empty command when there is no extensionElements list + return {}; + } + + return cmdHelper.removeElementsFromList(element, extensionElements, 'values', 'extensionElements', [entry]); +}; + +module.exports = ExtensionElementsHelper; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/FormHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/FormHelper.js new file mode 100644 index 00000000..2c11459e --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/FormHelper.js @@ -0,0 +1,97 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + getExtensionElements = require('./ExtensionElementsHelper').getExtensionElements; + +var FormHelper = {}; + +module.exports = FormHelper; + +/** + * Return form data from business object or undefined if none exist + * + * @param {djs.model.Base} element + * + * @return {ModdleElement|undefined} formData + * + * 此方法废弃 + * + */ +FormHelper.getFormData = function(element) { + /* var bo = getBusinessObject(element); + + var formFields = getExtensionElements(bo, 'activiti:FormProperty'); + + var formData = {} + + if (typeof formData !== 'undefined') { + return formData[0]; + }*/ + return {}; +}; + + +/** + * Return all form fields existing in the business object, and + * an empty array if none exist. + * + * @param {djs.model.Base} element + * + * @return {Array} a list of form field objects + */ +FormHelper.getFormFields = function(element) { + + /**直接获取 ExtensionElements的 activiti:FormProperty元素*/ + var bo = getBusinessObject(element); + + var formFields = getExtensionElements(bo, 'activiti:FormProperty'); + + return formFields || []; +}; + + +/** + * Get a form field from the business object at given index + * + * @param {djs.model.Base} element + * @param {number} idx + * + * @return {ModdleElement} the form field + */ +FormHelper.getFormField = function(element, idx) { + + var formFields = this.getFormFields(element); + + return formFields[idx]; +}; + + +/** + * Get all constraints for a specific form field from the business object + * + * @param {ModdleElement} formField + * + * @return {Array} a list of constraint objects + */ +FormHelper.getConstraints = function(formField) { + if (formField && formField.validation && formField.validation.constraints) { + return formField.validation.constraints; + } + return []; +}; + + +/** + * Get all activiti:value objects for a specific form field from the business object + * + * @param {ModdleElement} formField + * + * @return {Array} a list of activiti:value objects + */ +FormHelper.getEnumValues = function(formField) { + if (formField && formField.values) { + return formField.values; + } + return []; +}; + diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ImplementationTypeHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ImplementationTypeHelper.js new file mode 100644 index 00000000..33f4c8fe --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ImplementationTypeHelper.js @@ -0,0 +1,192 @@ +'use strict'; + +var ModelUtil = require('bpmn-js/lib/util/ModelUtil'), + is = ModelUtil.is, + getBusinessObject = ModelUtil.getBusinessObject; + +var eventDefinitionHelper = require('./EventDefinitionHelper'); +var extensionsElementHelper = require('./ExtensionElementsHelper'); + +var ImplementationTypeHelper = {}; + +module.exports = ImplementationTypeHelper; + +/** + * Returns 'true' if the given element is 'activiti:ServiceTaskLike' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isServiceTaskLike = function(element) { + return is(element, 'activiti:ServiceTaskLike'); +}; + +/** + * Returns 'true' if the given element is 'activiti:DmnCapable' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isDmnCapable = function(element) { + return is(element, 'activiti:DmnCapable'); +}; + +/** + * Returns 'true' if the given element is 'activiti:ExternalCapable' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isExternalCapable = function(element) { + return is(element, 'activiti:ExternalCapable'); +}; + +/** + * Returns 'true' if the given element is 'activiti:TaskListener' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isTaskListener = function(element) { + return is(element, 'activiti:TaskListener'); +}; + +/** + * Returns 'true' if the given element is 'activiti:ExecutionListener' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isExecutionListener = function(element) { + return is(element, 'activiti:ExecutionListener'); +}; + +/** + * Returns 'true' if the given element is 'activiti:ExecutionListener' or + * 'activiti:TaskListener' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isListener = function(element) { + return this.isTaskListener(element) || this.isExecutionListener(element); +}; + +/** + * Returns 'true' if the given element is 'bpmn:SequenceFlow' + * + * @param {djs.model.Base} element + * + * @return {boolean} a boolean value + */ +ImplementationTypeHelper.isSequenceFlow = function(element) { + return is(element, 'bpmn:SequenceFlow'); +}; + +/** + * Get a 'activiti:ServiceTaskLike' business object. + * + * If the given element is not a 'activiti:ServiceTaskLike', then 'false' + * is returned. + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} the 'activiti:ServiceTaskLike' business object + */ +ImplementationTypeHelper.getServiceTaskLikeBusinessObject = function(element) { + + if (is(element, 'bpmn:IntermediateThrowEvent') || is(element, 'bpmn:EndEvent')) { + + // change business object to 'messageEventDefinition' when + // the element is a message intermediate throw event or message end event + // because the activiti extensions (e.g. activiti:class) are in the message + // event definition tag and not in the intermediate throw event or end event tag + var messageEventDefinition = eventDefinitionHelper.getMessageEventDefinition(element); + if (messageEventDefinition) { + element = messageEventDefinition; + } + } + + return this.isServiceTaskLike(element) && getBusinessObject(element); + +}; + +/** + * Returns the implementation type of the given element. + * + * Possible implementation types are: + * - dmn + * - connector + * - external + * - class + * - expression + * - delegateExpression + * - script + * - or undefined, when no matching implementation type is found + * + * @param {djs.model.Base} element + * + * @return {String} the implementation type + */ +ImplementationTypeHelper.getImplementationType = function(element) { + + var bo = this.getServiceTaskLikeBusinessObject(element); + + if (!bo) { + if (this.isListener(element)) { + bo = element; + } else { + return; + } + } + + if (this.isDmnCapable(bo)) { + var decisionRef = bo.get('activiti:decisionRef'); + if (typeof decisionRef !== 'undefined') { + return 'dmn'; + } + } + + if (this.isServiceTaskLike(bo)) { + var connectors = extensionsElementHelper.getExtensionElements(bo, 'activiti:Connector'); + if (typeof connectors !== 'undefined') { + return 'connector'; + } + } + + if (this.isExternalCapable(bo)) { + var type = bo.get('activiti:type'); + if (type === 'external') { + return 'external'; + } + } + + var cls = bo.get('activiti:class'); + if (typeof cls !== 'undefined') { + return 'class'; + } + + var expression = bo.get('activiti:expression'); + if (typeof expression !== 'undefined') { + return 'expression'; + } + + var delegateExpression = bo.get('activiti:delegateExpression'); + if (typeof delegateExpression !== 'undefined') { + return 'delegateExpression'; + } + + if (this.isListener(bo)) { + var script = bo.get('script'); + if (typeof script !== 'undefined') { + return 'script'; + } + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/InputOutputHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/InputOutputHelper.js new file mode 100644 index 00000000..f2ad3a53 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/InputOutputHelper.js @@ -0,0 +1,144 @@ +'use strict'; + +var ModelUtil = require('bpmn-js/lib/util/ModelUtil'), + is = ModelUtil.is, + getBusinessObject = ModelUtil.getBusinessObject; + +var extensionElementsHelper = require('./ExtensionElementsHelper'), + implementationTypeHelper = require('./ImplementationTypeHelper'); + +var InputOutputHelper = {}; + +module.exports = InputOutputHelper; + +function getElements(bo, type, prop) { + var elems = extensionElementsHelper.getExtensionElements(bo, type) || []; + return !prop ? elems : (elems[0] || {})[prop] || []; +} + +function getParameters(element, prop, insideConnector) { + var inputOutput = InputOutputHelper.getInputOutput(element, insideConnector); + return (inputOutput && inputOutput.get(prop)) || []; +} + +/** + * Get a inputOutput from the business object + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {ModdleElement} the inputOutput object + */ +InputOutputHelper.getInputOutput = function(element, insideConnector) { + if (!insideConnector) { + var bo = getBusinessObject(element); + return (getElements(bo, 'activiti:InputOutput') || [])[0]; + } + var connector = this.getConnector(element); + return connector && connector.get('inputOutput'); +}; + +/** + * Get a connector from the business object + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} the connector object + */ +InputOutputHelper.getConnector = function(element) { + var bo = implementationTypeHelper.getServiceTaskLikeBusinessObject(element); + return bo && (getElements(bo, 'activiti:Connector') || [])[0]; +}; + +/** + * Return all input parameters existing in the business object, and + * an empty array if none exist. + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {Array} a list of input parameter objects + */ +InputOutputHelper.getInputParameters = function(element, insideConnector) { + return getParameters.apply(this, [ element, 'inputParameters', insideConnector ]); +}; + +/** + * Return all output parameters existing in the business object, and + * an empty array if none exist. + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {Array} a list of output parameter objects + */ +InputOutputHelper.getOutputParameters = function(element, insideConnector) { + return getParameters.apply(this, [ element, 'outputParameters', insideConnector ]); +}; + +/** + * Get a input parameter from the business object at given index + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * @param {number} idx + * + * @return {ModdleElement} input parameter + */ +InputOutputHelper.getInputParameter = function(element, insideConnector, idx) { + return this.getInputParameters(element, insideConnector)[idx]; +}; + +/** + * Get a output parameter from the business object at given index + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * @param {number} idx + * + * @return {ModdleElement} output parameter + */ +InputOutputHelper.getOutputParameter = function(element, insideConnector, idx) { + return this.getOutputParameters(element, insideConnector)[idx]; +}; + +/** + * Returns 'true' if the given element supports inputOutput + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {boolean} a boolean value + */ +InputOutputHelper.isInputOutputSupported = function(element, insideConnector) { + + if (insideConnector) { + return true; + } + + var bo = getBusinessObject(element); + + return ( + is(bo, 'bpmn:FlowNode') && !( + is(bo, 'bpmn:StartEvent') || + is(bo, 'bpmn:Gateway') || + is(bo, 'bpmn:BoundaryEvent') || + ( + is(bo, 'bpmn:SubProcess') && bo.get('triggeredByEvent') + ) + ) + ); +}; + +/** + * Returns 'true' if the given element supports output parameters + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {boolean} a boolean value + */ +InputOutputHelper.areOutputParametersSupported = function(element, insideConnector) { + var bo = getBusinessObject(element); + return insideConnector || (!is(bo, 'bpmn:EndEvent') && !bo.loopCharacteristics); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ParticipantHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ParticipantHelper.js new file mode 100644 index 00000000..91d5d096 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/helper/ParticipantHelper.js @@ -0,0 +1,36 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + cmdHelper = require('./CmdHelper'); + + +var ParticipantHelper = {}; + +module.exports = ParticipantHelper; + +ParticipantHelper.modifyProcessBusinessObject = function(element, property, values) { + if (!is(element, 'bpmn:Participant')) { + return {}; + } + + var bo = getBusinessObject(element).get('processRef'), + properties = {}; + + properties[property] = values[property]; + + return cmdHelper.updateBusinessObject(element, bo, properties); +}; + +ParticipantHelper.getProcessBusinessObject = function(element, propertyName) { + if (!is(element, 'bpmn:Participant')) { + return {}; + } + + var bo = getBusinessObject(element).get('processRef'), + properties = {}; + + properties[propertyName] = bo.get(propertyName); + + return properties; +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/index.js new file mode 100644 index 00000000..c2c227c1 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/index.js @@ -0,0 +1,8 @@ +module.exports = { + __depends__: [ + require('./index'), + require('diagram-js/lib/i18n/translate').default + ], + __init__: [ 'propertiesPanel' ], + propertiesPanel: [ 'type', require('./PropertiesPanel') ] +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/popup.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/popup.js new file mode 100644 index 00000000..2b8257b9 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/popup.js @@ -0,0 +1,103 @@ +'use strict'; + +var domQuery = require('min-dom').query, + domClasses = require('min-dom').classes, + domify = require('min-dom').domify, + bind = require('lodash/bind'); + +/** + * @class + * @constructor + */ +function Popup(options) { + options = options || {}; + this.template = options.template || this.template; + var el = this.el = domify(this.template); + + this.header = domQuery('.popup-header', el); + this.body = domQuery('.popup-body', el); + this.footer = domQuery('.popup-footer', el); + + document.body.appendChild(el); + + this._attachEvents(); +} + +Popup.prototype.template = '' + + '' + + '' + + 'Close' + + '' + + '' + + '' + + '' + + ''; + + + +Popup.prototype._attachEvents = function() { + var self = this; + var events = this.events; + var el = this.el; + + Object.keys(events).forEach(function(instruction) { + var cb = bind(self[events[instruction]], self); + var parts = instruction.split(' '); + var evtName = parts.shift(); + var target = parts.length ? parts.shift() : false; + target = target ? domQuery(target, el) : el; + if (!target) { return; } + target.addEventListener(evtName, cb); + }); +}; + +Popup.prototype._detachEvents = function() { + var self = this; + var events = this.events; + var el = this.el; + + Object.keys(events).forEach(function(instruction) { + var cb = bind(self[events[instruction]], self); + var parts = instruction.split(' '); + var evtName = parts.shift(); + var target = parts.length ? parts.shift() : false; + target = target ? domQuery(target, el) : el; + if (!target) { return; } + target.removeEventListener(evtName, cb); + }); +}; + +Popup.prototype.events = { + // 'keydown:esc': '_handleClose', + 'click .underlay': '_handleClose', + 'click .popup-close': '_handleClose' +}; + + +Popup.prototype._handleClose = function(evt) { + this.close(); +}; + + +Popup.prototype.open = function(content) { + domClasses(this.el).add('open'); +}; + +Popup.prototype.close = function() { + domClasses(this.el).remove('open'); +}; + +Popup.prototype.remove = function() { + this._detachEvents(); + if (document.body.contains(this.el)) { + document.body.removeChild(this.el); + } +}; + +var popup; +module.exports = function() { + if (!popup) { + popup = new Popup(); + } + return popup; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/ActivitiPropertiesProvider.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/ActivitiPropertiesProvider.js new file mode 100644 index 00000000..2164cf6d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/ActivitiPropertiesProvider.js @@ -0,0 +1,542 @@ +'use strict'; + +var inherits = require('inherits'); + +var PropertiesActivator = require('../../PropertiesActivator'); + +var asyncCapableHelper = require('../../helper/AsyncCapableHelper'), + ImplementationTypeHelper = require('../../helper/ImplementationTypeHelper'); + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +// bpmn properties +var processProps = require('../../provider/bpmn/parts/ProcessProps'), + eventProps = require('../../provider/bpmn/parts/EventProps'), + linkProps = require('../../provider/bpmn/parts/LinkProps'), + documentationProps = require('../../provider/bpmn/parts/DocumentationProps'), + idProps = require('../../provider/bpmn/parts/IdProps'), + nameProps = require('../../provider/bpmn/parts/NameProps'), + executableProps = require('../../provider/bpmn/parts/ExecutableProps'); + +// activiti properties +var serviceTaskDelegateProps = require('./parts/ServiceTaskDelegateProps'), + userTaskProps = require('./parts/UserTaskProps'), + asynchronousContinuationProps = require('./parts/AsynchronousContinuationProps'), + callActivityProps = require('./parts/CallActivityProps'), + multiInstanceProps = require('./parts/MultiInstanceLoopProps'), + conditionalProps = require('./parts/ConditionalProps'), + scriptProps = require('./parts/ScriptTaskProps'), + errorProps = require('./parts/ErrorEventProps'), + formProps = require('./parts/FormProps'), + startEventInitiator = require('./parts/StartEventInitiator'), + variableMapping = require('./parts/VariableMappingProps'), + versionTag = require('./parts/VersionTagProps'); + +var listenerProps = require('./parts/ListenerProps'), + listenerDetails = require('./parts/ListenerDetailProps'), + listenerFields = require('./parts/ListenerFieldInjectionProps'); + +var elementTemplateChooserProps = require('./element-templates/parts/ChooserProps'), + elementTemplateCustomProps = require('./element-templates/parts/CustomProps'); + +// Input/Output +var inputOutput = require('./parts/InputOutputProps'), + inputOutputParameter = require('./parts/InputOutputParameterProps'); + +// Connector +var connectorDetails = require('./parts/ConnectorDetailProps'), + connectorInputOutput = require('./parts/ConnectorInputOutputProps'), + connectorInputOutputParameter = require('./parts/ConnectorInputOutputParameterProps'); + +// properties +var properties = require('./parts/PropertiesProps'); + +// job configuration +var jobConfiguration = require('./parts/JobConfigurationProps'); + +// history time to live +var historyTimeToLive = require('./parts/HistoryTimeToLiveProps'); + +// candidate starter groups/users +var candidateStarter = require('./parts/CandidateStarterProps'); + +// tasklist +var tasklist = require('./parts/TasklistProps'); + +// external task configuration +var externalTaskConfiguration = require('./parts/ExternalTaskConfigurationProps'); + +// field injection +var fieldInjections = require('./parts/FieldInjectionProps'); + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + eventDefinitionHelper = require('../../helper/EventDefinitionHelper'), + implementationTypeHelper = require('../../helper/ImplementationTypeHelper'); + +// helpers //////////////////////////////////////// + +var isExternalTaskPriorityEnabled = function(element) { + var businessObject = getBusinessObject(element); + + // show only if element is a process, a participant ... + if (is(element, 'bpmn:Process') || is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + return true; + } + + var externalBo = ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element), + isExternalTask = ImplementationTypeHelper.getImplementationType(externalBo) === 'external'; + + // ... or an external task with selected external implementation type + return !!ImplementationTypeHelper.isExternalCapable(externalBo) && isExternalTask; +}; + +var isJobConfigEnabled = function(element) { + var businessObject = getBusinessObject(element); + + if (is(element, 'bpmn:Process') || is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + return true; + } + + // async behavior + var bo = getBusinessObject(element); + if (asyncCapableHelper.isAsyncBefore(bo) || asyncCapableHelper.isAsyncAfter(bo)) { + return true; + } + + // timer definition + if (is(element, 'bpmn:Event')) { + return !!eventDefinitionHelper.getTimerEventDefinition(element); + } + + return false; +}; + +var getInputOutputParameterLabel = function(param, translate) { + + if (is(param, 'activiti:InputParameter')) { + return translate('Input Parameter'); + } + + if (is(param, 'activiti:OutputParameter')) { + return translate('Output Parameter'); + } + + return ''; +}; + +var getListenerLabel = function(param, translate) { + + if (is(param, 'activiti:ExecutionListener')) { + return translate('Execution Listener'); + } + + if (is(param, 'activiti:TaskListener')) { + return translate('Task Listener'); + } + + return ''; +}; + +var PROCESS_KEY_HINT = 'This maps to the process definition key.'; +var TASK_KEY_HINT = 'This maps to the task definition key.'; + +function createGeneralTabGroups( + element, canvas, bpmnFactory, + elementRegistry, elementTemplates, translate) { + + // refer to target element for external labels + element = element.labelTarget || element; + + var generalGroup = { + id: 'general', + label: translate('General'), + entries: [] + }; + + var idOptions; + var processOptions; + + if (is(element, 'bpmn:Process')) { + idOptions = { description: PROCESS_KEY_HINT }; + } + + if (is(element, 'bpmn:UserTask')) { + idOptions = { description: TASK_KEY_HINT }; + } + + if (is(element, 'bpmn:Participant')) { + processOptions = { processIdDescription: PROCESS_KEY_HINT }; + } + + idProps(generalGroup, element, translate, idOptions); + nameProps(generalGroup, element, bpmnFactory, canvas, translate); + processProps(generalGroup, element, translate, processOptions); + versionTag(generalGroup, element, translate); + executableProps(generalGroup, element, translate); + elementTemplateChooserProps(generalGroup, element, elementTemplates, translate); + + var customFieldsGroups = elementTemplateCustomProps(element, elementTemplates, bpmnFactory, translate); + + var detailsGroup = { + id: 'details', + label: translate('Details'), + entries: [] + }; + serviceTaskDelegateProps(detailsGroup, element, bpmnFactory, translate); + userTaskProps(detailsGroup, element, translate); + scriptProps(detailsGroup, element, bpmnFactory, translate); + linkProps(detailsGroup, element, translate); + callActivityProps(detailsGroup, element, bpmnFactory, translate); + eventProps(detailsGroup, element, bpmnFactory, elementRegistry, translate); + errorProps(detailsGroup, element, bpmnFactory, translate); + conditionalProps(detailsGroup, element, bpmnFactory, translate); + startEventInitiator(detailsGroup, element, translate); // this must be the last element of the details group! + + var multiInstanceGroup = { + id: 'multiInstance', + label: translate('Multi Instance'), + entries: [] + }; + multiInstanceProps(multiInstanceGroup, element, bpmnFactory, translate); + + var asyncGroup = { + id : 'async', + label: translate('Asynchronous Continuations'), + entries : [] + }; + asynchronousContinuationProps(asyncGroup, element, bpmnFactory, translate); + + var jobConfigurationGroup = { + id : 'jobConfiguration', + label : translate('Job Configuration'), + entries : [], + enabled: isJobConfigEnabled + }; + jobConfiguration(jobConfigurationGroup, element, bpmnFactory, translate); + + var externalTaskGroup = { + id : 'externalTaskConfiguration', + label : translate('External Task Configuration'), + entries : [], + enabled: isExternalTaskPriorityEnabled + }; + externalTaskConfiguration(externalTaskGroup, element, bpmnFactory, translate); + + + var candidateStarterGroup = { + id: 'candidateStarterConfiguration', + label: translate('Candidate Starter Configuration'), + entries: [] + }; + candidateStarter(candidateStarterGroup, element, bpmnFactory, translate); + + var historyTimeToLiveGroup = { + id: 'historyConfiguration', + label: translate('History Configuration'), + entries: [] + }; + historyTimeToLive(historyTimeToLiveGroup, element, bpmnFactory, translate); + + var tasklistGroup = { + id: 'tasklist', + label: translate('Tasklist Configuration'), + entries: [] + }; + tasklist(tasklistGroup, element, bpmnFactory, translate); + + var documentationGroup = { + id: 'documentation', + label: translate('Documentation'), + entries: [] + }; + documentationProps(documentationGroup, element, bpmnFactory, translate); + + var groups = []; + groups.push(generalGroup); + customFieldsGroups.forEach(function(group) { + groups.push(group); + }); + groups.push(detailsGroup); + groups.push(externalTaskGroup); + groups.push(multiInstanceGroup); + groups.push(asyncGroup); + groups.push(jobConfigurationGroup); + groups.push(candidateStarterGroup); + groups.push(historyTimeToLiveGroup); + groups.push(tasklistGroup); + groups.push(documentationGroup); + + return groups; +} + +function createVariablesTabGroups(element, bpmnFactory, elementRegistry, translate) { + var variablesGroup = { + id : 'variables', + label : translate('Variables'), + entries: [] + }; + variableMapping(variablesGroup, element, bpmnFactory, translate); + + return [ + variablesGroup + ]; +} + +function createFormsTabGroups(element, bpmnFactory, elementRegistry, translate) { + var formGroup = { + id : 'forms', + label : translate('Forms'), + entries: [] + }; + formProps(formGroup, element, bpmnFactory, translate); + + return [ + formGroup + ]; +} + +function createListenersTabGroups(element, bpmnFactory, elementRegistry, translate) { + + var listenersGroup = { + id : 'listeners', + label: translate('Listeners'), + entries: [] + }; + + var options = listenerProps(listenersGroup, element, bpmnFactory, translate); + + var listenerDetailsGroup = { + id: 'listener-details', + entries: [], + enabled: function(element, node) { + return options.getSelectedListener(element, node); + }, + label: function(element, node) { + var param = options.getSelectedListener(element, node); + return getListenerLabel(param, translate); + } + }; + + listenerDetails(listenerDetailsGroup, element, bpmnFactory, options, translate); + + var listenerFieldsGroup = { + id: 'listener-fields', + label: translate('Field Injection'), + entries: [], + enabled: function(element, node) { + return options.getSelectedListener(element, node); + } + }; + + listenerFields(listenerFieldsGroup, element, bpmnFactory, options, translate); + + return [ + listenersGroup, + listenerDetailsGroup, + listenerFieldsGroup + ]; +} + +function createInputOutputTabGroups(element, bpmnFactory, elementRegistry, translate) { + + var inputOutputGroup = { + id: 'input-output', + label: translate('Parameters'), + entries: [] + }; + + var options = inputOutput(inputOutputGroup, element, bpmnFactory, translate); + + var inputOutputParameterGroup = { + id: 'input-output-parameter', + entries: [], + enabled: function(element, node) { + return options.getSelectedParameter(element, node); + }, + label: function(element, node) { + var param = options.getSelectedParameter(element, node); + return getInputOutputParameterLabel(param, translate); + } + }; + + inputOutputParameter(inputOutputParameterGroup, element, bpmnFactory, options, translate); + + return [ + inputOutputGroup, + inputOutputParameterGroup + ]; +} + +function createConnectorTabGroups(element, bpmnFactory, elementRegistry, translate) { + var connectorDetailsGroup = { + id: 'connector-details', + label: translate('Details'), + entries: [] + }; + + connectorDetails(connectorDetailsGroup, element, bpmnFactory, translate); + + var connectorInputOutputGroup = { + id: 'connector-input-output', + label: translate('Input/Output'), + entries: [] + }; + + var options = connectorInputOutput(connectorInputOutputGroup, element, bpmnFactory, translate); + + var connectorInputOutputParameterGroup = { + id: 'connector-input-output-parameter', + entries: [], + enabled: function(element, node) { + return options.getSelectedParameter(element, node); + }, + label: function(element, node) { + var param = options.getSelectedParameter(element, node); + return getInputOutputParameterLabel(param, translate); + } + }; + + connectorInputOutputParameter(connectorInputOutputParameterGroup, element, bpmnFactory, options, translate); + + return [ + connectorDetailsGroup, + connectorInputOutputGroup, + connectorInputOutputParameterGroup + ]; +} + +function createFieldInjectionsTabGroups(element, bpmnFactory, elementRegistry, translate) { + + var fieldGroup = { + id: 'field-injections-properties', + label: translate('Field Injections'), + entries: [] + }; + + fieldInjections(fieldGroup, element, bpmnFactory, translate); + + return [ + fieldGroup + ]; +} + +function createExtensionElementsGroups(element, bpmnFactory, elementRegistry, translate) { + + var propertiesGroup = { + id : 'extensionElements-properties', + label: translate('Properties'), + entries: [] + }; + properties(propertiesGroup, element, bpmnFactory, translate); + + return [ + propertiesGroup + ]; +} + +// activiti Properties Provider ///////////////////////////////////// + + +/** + * A properties provider for activiti related properties. + * + * @param {EventBus} eventBus + * @param {Canvas} canvas + * @param {BpmnFactory} bpmnFactory + * @param {ElementRegistry} elementRegistry + * @param {ElementTemplates} elementTemplates + * @param {Translate} translate + */ +function ActivitiPropertiesProvider( + eventBus, canvas, bpmnFactory, + elementRegistry, elementTemplates, translate) { + + PropertiesActivator.call(this, eventBus); + + this.getTabs = function(element) { + + var generalTab = { + id: 'general', + label: translate('General'), + groups: createGeneralTabGroups( + element, canvas, bpmnFactory, + elementRegistry, elementTemplates, translate) + }; + + var variablesTab = { + id: 'variables', + label: translate('Variables'), + groups: createVariablesTabGroups(element, bpmnFactory, elementRegistry, translate) + }; + + var formsTab = { + id: 'forms', + label: translate('Forms'), + groups: createFormsTabGroups(element, bpmnFactory, elementRegistry, translate) + }; + + var listenersTab = { + id: 'listeners', + label: translate('Listeners'), + groups: createListenersTabGroups(element, bpmnFactory, elementRegistry, translate), + enabled: function(element) { + return !eventDefinitionHelper.getLinkEventDefinition(element) + || (!is(element, 'bpmn:IntermediateThrowEvent') + && eventDefinitionHelper.getLinkEventDefinition(element)); + } + }; + + var inputOutputTab = { + id: 'input-output', + label: translate('Input/Output'), + groups: createInputOutputTabGroups(element, bpmnFactory, elementRegistry, translate) + }; + + var connectorTab = { + id: 'connector', + label: translate('Connector'), + groups: createConnectorTabGroups(element, bpmnFactory, elementRegistry, translate), + enabled: function(element) { + var bo = implementationTypeHelper.getServiceTaskLikeBusinessObject(element); + return bo && implementationTypeHelper.getImplementationType(bo) === 'connector'; + } + }; + + var fieldInjectionsTab = { + id: 'field-injections', + label: translate('Field Injections'), + groups: createFieldInjectionsTabGroups(element, bpmnFactory, elementRegistry, translate) + }; + + var extensionsTab = { + id: 'extensionElements', + label: translate('Extensions'), + groups: createExtensionElementsGroups(element, bpmnFactory, elementRegistry, translate) + }; + + return [ + generalTab, + variablesTab, + connectorTab, + formsTab, + listenersTab, + inputOutputTab, + fieldInjectionsTab, + extensionsTab + ]; + }; + +} + +ActivitiPropertiesProvider.$inject = [ + 'eventBus', + 'canvas', + 'bpmnFactory', + 'elementRegistry', + 'elementTemplates', + 'translate' +]; + +inherits(ActivitiPropertiesProvider, PropertiesActivator); + +module.exports = ActivitiPropertiesProvider; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CreateHelper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CreateHelper.js new file mode 100644 index 00000000..c8ea8936 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CreateHelper.js @@ -0,0 +1,251 @@ +'use strict'; + +var assign = require('lodash/assign'); + +/** + * Create an input parameter representing the given + * binding and value. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createInputParameter(binding, value, bpmnFactory) { + var scriptFormat = binding.scriptFormat, + parameterValue, + parameterDefinition; + + if (scriptFormat) { + parameterDefinition = bpmnFactory.create('activiti:Script', { + scriptFormat: scriptFormat, + value: value + }); + } else { + parameterValue = value; + } + + return bpmnFactory.create('activiti:InputParameter', { + name: binding.name, + value: parameterValue, + definition: parameterDefinition + }); +} + +module.exports.createInputParameter = createInputParameter; + + +/** + * Create an output parameter representing the given + * binding and value. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createOutputParameter(binding, value, bpmnFactory) { + var scriptFormat = binding.scriptFormat, + parameterValue, + parameterDefinition; + + if (scriptFormat) { + parameterDefinition = bpmnFactory.create('activiti:Script', { + scriptFormat: scriptFormat, + value: binding.source + }); + } else { + parameterValue = binding.source; + } + + return bpmnFactory.create('activiti:OutputParameter', { + name: value, + value: parameterValue, + definition: parameterDefinition + }); +} + +module.exports.createOutputParameter = createOutputParameter; + + +/** + * Create activiti property from the given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiProperty(binding, value, bpmnFactory) { + return bpmnFactory.create('activiti:Property', { + name: binding.name, + value: value || '' + }); +} + +module.exports.createActivitiProperty = createActivitiProperty; + + +/** + * Create activiti:in element from given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiIn(binding, value, bpmnFactory) { + + var properties = createActivitiInOutAttrs(binding, value); + + return bpmnFactory.create('activiti:In', properties); +} + +module.exports.createActivitiIn = createActivitiIn; + + +/** + * Create activiti:in with businessKey element from given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiInWithBusinessKey(binding, value, bpmnFactory) { + return bpmnFactory.create('activiti:In', { + businessKey: value + }); +} + +module.exports.createActivitiInWithBusinessKey = createActivitiInWithBusinessKey; + + +/** + * Create activiti:out element from given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiOut(binding, value, bpmnFactory) { + var properties = createActivitiInOutAttrs(binding, value); + + return bpmnFactory.create('activiti:Out', properties); +} + +module.exports.createActivitiOut = createActivitiOut; + + +/** + * Create activiti:executionListener element containing an inline script from given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiExecutionListenerScript(binding, value, bpmnFactory) { + var scriptFormat = binding.scriptFormat, + parameterValue, + parameterDefinition; + + if (scriptFormat) { + parameterDefinition = bpmnFactory.create('activiti:Script', { + scriptFormat: scriptFormat, + value: value + }); + } else { + parameterValue = value; + } + + return bpmnFactory.create('activiti:ExecutionListener', { + event: binding.event, + value: parameterValue, + script: parameterDefinition + }); +} + +module.exports.createActivitiExecutionListenerScript = createActivitiExecutionListenerScript; + +/** + * Create activiti:field element containing string or expression from given binding. + * + * @param {PropertyBinding} binding + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} + */ +function createActivitiFieldInjection(binding, value, bpmnFactory) { + var DEFAULT_PROPS = { + 'string': undefined, + 'expression': undefined, + 'name': undefined + }; + + var props = assign({}, DEFAULT_PROPS); + + if (!binding.expression) { + props.string = value; + } else { + props.expression = value; + } + props.name = binding.name; + + return bpmnFactory.create('activiti:Field', props); +} +module.exports.createActivitiFieldInjection = createActivitiFieldInjection; + + +// helpers //////////////////////////// + +/** + * Create properties for activiti:in and activiti:out types. + */ +function createActivitiInOutAttrs(binding, value) { + + var properties = {}; + + // activiti:in source(Expression) target + if (binding.target) { + + properties.target = binding.target; + + if (binding.expression) { + properties.sourceExpression = value; + } else { + properties.source = value; + } + } else + + // activiti:(in|out) variables local + if (binding.variables) { + properties.variables = 'all'; + + if (binding.variables === 'local') { + properties.local = true; + } + } + + // activiti:out source(Expression) target + else { + properties.target = value; + + [ 'source', 'sourceExpression' ].forEach(function(k) { + if (binding[k]) { + properties[k] = binding[k]; + } + }); + } + + return properties; +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CustomElementsPropertiesActivator.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CustomElementsPropertiesActivator.js new file mode 100644 index 00000000..1db3ceae --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/CustomElementsPropertiesActivator.js @@ -0,0 +1,132 @@ +'use strict'; + +var inherits = require('inherits'); + +var getTemplate = require('./Helper').getTemplate; + +var PropertiesActivator = require('../../../PropertiesActivator'); + +var HIGHER_PRIORITY = 1100; + +/** + * Applies template visibility settings. + * + * Controlled using `entriesVisible` on template config object: + * + * ```json + * "entriesVisible": { + * "_all": true|false, + * "entryName": true|false, + * ... + * } + * ``` + * + * @param {EventBus} eventBus + * @param {ElementTemplates} elementTemplates + */ +function CustomElementsPropertiesActivator(eventBus, elementTemplates) { + PropertiesActivator.call(this, eventBus, HIGHER_PRIORITY); + + this.isEntryVisible = function(entry, element) { + + var template = getTemplate(element, elementTemplates); + + if (template && !isEntryVisible(entry, template)) { + return false; + } + }; + + this.isPropertyEditable = function(entry, propertyName, element) { + + var template = getTemplate(element, elementTemplates); + + if (template && !isEntryEditable(entry, template)) { + return false; + } + }; +} + +CustomElementsPropertiesActivator.$inject = [ 'eventBus', 'elementTemplates' ]; + +inherits(CustomElementsPropertiesActivator, PropertiesActivator); + +module.exports = CustomElementsPropertiesActivator; + + + +// helpers //////////////////////////////////// + + +var CUSTOM_PROPERTIES_PATTERN = /^custom-/; + +var DEFAULT_ENTRIES_VISIBLE = { + _all: false, + id: true, + name: true +}; + +function isCustomEntry(entry) { + return CUSTOM_PROPERTIES_PATTERN.test(entry.id); +} + +function isEntryVisible(entry, template) { + + var entryId = entry.id; + + if (entryId === 'elementTemplate-chooser' || isCustomEntry(entry)) { + return true; + } + + var entriesVisible = template.entriesVisible || DEFAULT_ENTRIES_VISIBLE; + + if (typeof entriesVisible === 'boolean') { + return entriesVisible; + } + + var defaultVisible = entriesVisible._all || false, + entryVisible = entriesVisible[entryId]; + + // d = true, e = false => false + // d = false, e = true => true + // d = false, e = false + return ( + (defaultVisible === true && entryVisible !== false) || + (defaultVisible === false && entryVisible === true) + ); +} + +function isEntryEditable(entry, template) { + + var property; + + if (isCustomEntry(entry)) { + property = getProperty(template, entry); + + return property && property.editable !== false; + } + + return true; +} + +function getProperty(template, entry) { + + var index; + var idx = entry.id.replace('custom-' + template.id + '-', ''); + if (idx.indexOf('-') !== -1) { + var indexes = idx.split('-'); + if (indexes.length == 2) { + var scopeName = indexes[0].replace(/_/g, ':'); + index = parseInt(indexes[1], 10); + if (scopeName && !isNaN(index)) { + return template.scopes[scopeName].properties[index]; + } + } + } else { + index = parseInt(idx, 10); + if (!isNaN(index)) { + return template.properties[index]; + } + } + + throw new Error('cannot extract property index for entry <' + entry.id + '>'); +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplates.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplates.js new file mode 100644 index 00000000..d17d78a8 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplates.js @@ -0,0 +1,56 @@ +'use strict'; + +var values = require('lodash/values'); + +/** + * The guy knowing all configured element templates. + * + * This registry won't validate. Use the {@link Validator} + * to verify a template is valid prior to adding it to + * this registry. + */ +function ElementTemplates() { + + this._templates = {}; + + /** + * Sets the known element templates. + * + * @param {Array} descriptors + * + * @return {ElementTemplates} + */ + this.set = function(descriptors) { + + var templates = this._templates = {}; + + descriptors.forEach(function(descriptor) { + templates[descriptor.id] = descriptor; + }); + + return this; + }; + + /** + * Get template descriptor with given id. + * + * @param {String} id + * + * @return {TemplateDescriptor} + */ + this.get = function(id) { + return this._templates[id]; + }; + + /** + * Return all known template descriptors. + * + * @return {Array} + */ + this.getAll = function() { + return values(this._templates); + }; + +} + +module.exports = ElementTemplates; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplatesLoader.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplatesLoader.js new file mode 100644 index 00000000..15dc3672 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/ElementTemplatesLoader.js @@ -0,0 +1,96 @@ +'use strict'; + +var Validator = require('./Validator'); + +/** + * The guy responsible for template loading. + * + * Provide the actual templates via the `config.elementTemplates`. + * + * That configuration can either be an array of template + * descriptors or a node style callback to retrieve + * the templates asynchronously. + * + * @param {Array|Function} loadTemplates + * @param {EventBus} eventBus + * @param {ElementTemplates} elementTemplates + */ +function ElementTemplatesLoader(loadTemplates, eventBus, elementTemplates) { + this._loadTemplates = loadTemplates; + this._eventBus = eventBus; + this._elementTemplates = elementTemplates; + + var self = this; + + eventBus.on('diagram.init', function() { + self.reload(); + }); +} + +module.exports = ElementTemplatesLoader; + +ElementTemplatesLoader.$inject = [ + 'config.elementTemplates', + 'eventBus', + 'elementTemplates' +]; + + +ElementTemplatesLoader.prototype.reload = function() { + + var self = this; + + var loadTemplates = this._loadTemplates; + + // no templates specified + if (typeof loadTemplates === 'undefined') { + return; + } + + // template loader function specified + if (typeof loadTemplates === 'function') { + + return loadTemplates(function(err, templates) { + + if (err) { + return self.templateErrors([ err ]); + } + + self.setTemplates(templates); + }); + } + + // templates array specified + if (loadTemplates.length) { + return this.setTemplates(loadTemplates); + } + +}; + +ElementTemplatesLoader.prototype.setTemplates = function(templates) { + + var elementTemplates = this._elementTemplates; + + var validator = new Validator().addAll(templates); + + var errors = validator.getErrors(), + validTemplates = validator.getValidTemplates(); + + elementTemplates.set(validTemplates); + + if (errors.length) { + this.templateErrors(errors); + } + + this.templatesChanged(); +}; + +ElementTemplatesLoader.prototype.templatesChanged = function() { + this._eventBus.fire('elementTemplates.changed'); +}; + +ElementTemplatesLoader.prototype.templateErrors = function(errors) { + this._eventBus.fire('elementTemplates.errors', { + errors: errors + }); +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Helper.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Helper.js new file mode 100644 index 00000000..d70c0685 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Helper.js @@ -0,0 +1,239 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + isAny = require('bpmn-js/lib/features/modeling/util/ModelingUtil').isAny; + +var find = require('lodash/find'); + + +var TEMPLATE_ATTR = 'activiti:modelerTemplate'; + +/** + * The BPMN 2.0 extension attribute name under + * which the element template is stored. + * + * @type {String} + */ +module.exports.TEMPLATE_ATTR = TEMPLATE_ATTR; + + +/** + * Get template id for a given diagram element. + * + * @param {djs.model.Base} element + * + * @return {String} + */ +function getTemplateId(element) { + + var bo = getBusinessObject(element); + + if (bo) { + return bo.get(TEMPLATE_ATTR); + } +} + +module.exports.getTemplateId = getTemplateId; + + +/** + * Get template of a given element. + * + * @param {Element} element + * @param {ElementTemplates} elementTemplates + * + * @return {TemplateDefinition} + */ +function getTemplate(element, elementTemplates) { + var id = getTemplateId(element); + + return id && elementTemplates.get(id); +} + +module.exports.getTemplate = getTemplate; + +/** + * Get default template for a given element. + * + * @param {Element} element + * @param {ElementTemplates} elementTemplates + * + * @return {TemplateDefinition} + */ +function getDefaultTemplate(element, elementTemplates) { + + // return first default template, if any exists + return ( + elementTemplates.getAll().filter(function(t) { + return isAny(element, t.appliesTo) && t.isDefault; + }) + )[0]; +} + +module.exports.getDefaultTemplate = getDefaultTemplate; + + +/** + * Find extension with given type in + * BPMN element, diagram element or ExtensionElement. + * + * @param {ModdleElement|djs.model.Base} element + * @param {String} type + * + * @return {ModdleElement} the extension + */ +function findExtension(element, type) { + var bo = getBusinessObject(element); + + var extensionElements; + + if (is(bo, 'bpmn:ExtensionElements')) { + extensionElements = bo; + } else { + extensionElements = bo.extensionElements; + } + + if (!extensionElements) { + return null; + } + + return find(extensionElements.get('values'), function(e) { + return is(e, type); + }); +} + +module.exports.findExtension = findExtension; + + +function findExtensions(element, types) { + var extensionElements = getExtensionElements(element); + + if (!extensionElements) { + return []; + } + + return extensionElements.get('values').filter(function(e) { + return isAny(e, types); + }); +} + +module.exports.findExtensions = findExtensions; + + +function findActivitiInOut(element, binding) { + + var extensionElements = getExtensionElements(element); + + if (!extensionElements) { + return; + } + + var matcher; + + if (binding.type === 'activiti:in') { + matcher = function(e) { + return is(e, 'activiti:In') && isInOut(e, binding); + }; + } else + if (binding.type === 'activiti:out') { + matcher = function(e) { + return is(e, 'activiti:Out') && isInOut(e, binding); + }; + } else + if (binding.type === 'activiti:in:businessKey') { + matcher = function(e) { + return is(e, 'activiti:In') && 'businessKey' in e; + }; + } + + return find(extensionElements.get('values'), matcher); +} + +module.exports.findActivitiInOut = findActivitiInOut; + +function findActivitiProperty(activitiProperties, binding) { + return find(activitiProperties.get('values'), function(p) { + return p.name === binding.name; + }); +} + +module.exports.findActivitiProperty = findActivitiProperty; + + +function findInputParameter(inputOutput, binding) { + var parameters = inputOutput.get('inputParameters'); + + return find(parameters, function(p) { + return p.name === binding.name; + }); +} + +module.exports.findInputParameter = findInputParameter; + + +function findOutputParameter(inputOutput, binding) { + var parameters = inputOutput.get('outputParameters'); + + return find(parameters, function(p) { + var value = p.value; + + if (!binding.scriptFormat) { + return value === binding.source; + } + + var definition = p.definition; + + if (!definition || binding.scriptFormat !== definition.scriptFormat) { + return false; + } + + return definition.value === binding.source; + }); +} + +module.exports.findOutputParameter = findOutputParameter; + + + +// helpers ///////////////////////////////// + +function getExtensionElements(element) { + var bo = getBusinessObject(element); + + if (is(bo, 'bpmn:ExtensionElements')) { + return bo; + } else { + return bo.extensionElements; + } +} + + +function isInOut(element, binding) { + + if (binding.type === 'activiti:in') { + // find based on target attribute + if (binding.target) { + return element.target === binding.target; + } + } + + if (binding.type === 'activiti:out') { + // find based on source / sourceExpression + if (binding.source) { + return element.source === binding.source; + } + + if (binding.sourceExpression) { + return element.sourceExpression === binding.sourceExpression; + } + } + + // find based variables / local combination + if (binding.variables) { + return element.variables === 'all' && ( + binding.variables !== 'local' || element.local + ); + } +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Validator.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Validator.js new file mode 100644 index 00000000..5745281a --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/Validator.js @@ -0,0 +1,303 @@ +'use strict'; + +var isArray = require('lodash/isArray'); +var isObject = require('lodash/isObject'); + +var DROPDOWN_TYPE = 'Dropdown'; + +var VALID_TYPES = [ 'String', 'Text', 'Boolean', 'Hidden', DROPDOWN_TYPE ]; + +var PROPERTY_TYPE = 'property', + ACTIVITI_PROPERTY_TYPE = 'activiti:property', + ACTIVITI_INPUT_PARAMETER_TYPE = 'activiti:inputParameter', + ACTIVITI_OUTPUT_PARAMETER_TYPE = 'activiti:outputParameter', + ACTIVITI_IN_TYPE = 'activiti:in', + ACTIVITI_OUT_TYPE = 'activiti:out', + ACTIVITI_IN_BUSINESS_KEY_TYPE = 'activiti:in:businessKey', + ACTIVITI_EXECUTION_LISTENER = 'activiti:executionListener', + ACTIVITI_FIELD = 'activiti:field'; + +var VALID_BINDING_TYPES = [ + PROPERTY_TYPE, + ACTIVITI_PROPERTY_TYPE, + ACTIVITI_INPUT_PARAMETER_TYPE, + ACTIVITI_OUTPUT_PARAMETER_TYPE, + ACTIVITI_IN_TYPE, + ACTIVITI_OUT_TYPE, + ACTIVITI_IN_BUSINESS_KEY_TYPE, + ACTIVITI_EXECUTION_LISTENER, + ACTIVITI_FIELD +]; + + +/** + * A element template validator. + */ +function Validator() { + + this._templatesById = {}; + + this._validTemplates = []; + this._errors = []; + + + /** + * Adds the templates. + * + * @param {Array} templates + * + * @return {Validator} self + */ + this.addAll = function(templates) { + + if (!isArray(templates)) { + this._logError('templates must be []'); + } else { + templates.forEach(this.add, this); + } + + return this; + }; + + /** + * Add the given element template, if it is valid. + * + * @param {TemplateDescriptor} template + * + * @return {Validator} self + */ + this.add = function(template) { + + var err = this._validateTemplate(template); + + if (!err) { + this._templatesById[template.id] = template; + + this._validTemplates.push(template); + } + + return this; + }; + + /** + * Validate given template and return error (if any). + * + * @param {TemplateDescriptor} template + * + * @return {Error} validation error, if any + */ + this._validateTemplate = function(template) { + + var err, + id = template.id, + appliesTo = template.appliesTo, + properties = template.properties, + scopes = template.scopes; + + if (!id) { + return this._logError('missing template id'); + } + + if (id in this._templatesById) { + return this._logError('template id <' + id + '> already used'); + } + + if (!isArray(appliesTo)) { + err = this._logError('missing appliesTo=[]', template); + } + + if (!isArray(properties)) { + err = this._logError('missing properties=[]', template); + } else { + if (!this._validateProperties(properties)) { + err = new Error('invalid properties'); + } + } + + if (scopes) { + err = this._validateScopes(template, scopes); + } + + return err; + }; + + this._validateScopes = function(template, scopes) { + + var err, + scope, + scopeName; + + if (!isObject(scopes) || isArray(scopes)) { + return this._logError('invalid scopes, should be scopes={}', template); + } + + for (scopeName in scopes) { + scope = scopes[scopeName]; + + if (!isObject(scope) || isArray(scope)) { + err = this._logError('invalid scope, should be scope={}', template); + } + + if (!isArray(scope.properties)) { + err = this._logError( + 'missing properties=[] in scope <' + scopeName + '>', template + ); + } else { + if (!this._validateProperties(scope.properties)) { + err = new Error('invalid properties in scope <' + scopeName + '>'); + } + } + } + + return err; + }; + + /** + * Validate properties and return false if any is invalid. + * + * @param {Array} properties + * + * @return {Boolean} true if all properties are valid + */ + this._validateProperties = function(properties) { + var validProperties = properties.filter(this._validateProperty, this); + + return properties.length === validProperties.length; + }; + + /** + * Validate property and return false, if there was + * a validation error. + * + * @param {PropertyDescriptor} property + * + * @return {Boolean} true if property is valid + */ + this._validateProperty = function(property) { + + var type = property.type, + binding = property.binding; + + var err; + + var bindingType = binding.type; + + if (VALID_TYPES.indexOf(type) === -1) { + err = this._logError( + 'invalid property type <' + type + '>; ' + + 'must be any of { ' + VALID_TYPES.join(', ') + ' }' + ); + } + + if (type === DROPDOWN_TYPE && bindingType !== ACTIVITI_EXECUTION_LISTENER) { + if (!isArray(property.choices)) { + err = this._logError( + 'must provide choices=[] with ' + DROPDOWN_TYPE + ' type' + ); + } else + + if (!property.choices.every(isDropdownChoiceValid)) { + err = this._logError( + '{ name, value } must be specified for ' + + DROPDOWN_TYPE + ' choices' + ); + } + } + + if (!binding) { + return this._logError('property missing binding'); + } + + if (VALID_BINDING_TYPES.indexOf(bindingType) === -1) { + err = this._logError( + 'invalid property.binding type <' + bindingType + '>; ' + + 'must be any of { ' + VALID_BINDING_TYPES.join(', ') + ' }' + ); + } + + if (bindingType === PROPERTY_TYPE || + bindingType === ACTIVITI_PROPERTY_TYPE || + bindingType === ACTIVITI_INPUT_PARAMETER_TYPE || + bindingType === ACTIVITI_FIELD) { + + if (!binding.name) { + err = this._logError( + 'property.binding <' + bindingType + '> requires name' + ); + } + } + + if (bindingType === ACTIVITI_OUTPUT_PARAMETER_TYPE) { + if (!binding.source) { + err = this._logError( + 'property.binding <' + bindingType + '> requires source' + ); + } + } + + if (bindingType === ACTIVITI_IN_TYPE) { + + if (!binding.variables && !binding.target) { + err = this._logError( + 'property.binding <' + bindingType + '> requires ' + + 'variables or target' + ); + } + } + + if (bindingType === ACTIVITI_OUT_TYPE) { + + if (!binding.variables && !binding.source && !binding.sourceExpression) { + err = this._logError( + 'property.binding <' + bindingType + '> requires ' + + 'variables, sourceExpression or source' + ); + } + } + + if (bindingType === ACTIVITI_EXECUTION_LISTENER) { + + if (type !== 'Hidden') { + err = this._logError( + 'invalid property type <' + type + '> for ' + ACTIVITI_EXECUTION_LISTENER + '; ' + + 'must be ' + ); + } + } + + return !err; + }; + + + this._logError = function(err, template) { + + if (typeof err === 'string') { + if (template) { + err = 'template(id: ' + template.id + ') ' + err; + } + + err = new Error(err); + } + + this._errors.push(err); + + return err; + }; + + this.getErrors = function() { + return this._errors; + }; + + this.getValidTemplates = function() { + return this._validTemplates; + }; +} + +module.exports = Validator; + + +// helpers /////////////////////////////////// + +function isDropdownChoiceValid(c) { + return 'name' in c && 'value' in c; +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/ChangeElementTemplateHandler.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/ChangeElementTemplateHandler.js new file mode 100644 index 00000000..f8f50473 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/ChangeElementTemplateHandler.js @@ -0,0 +1,471 @@ +'use strict'; + +var findExtension = require('../Helper').findExtension, + findExtensions = require('../Helper').findExtensions; + +var createActivitiProperty = require('../CreateHelper').createActivitiProperty, + createInputParameter = require('../CreateHelper').createInputParameter, + createOutputParameter = require('../CreateHelper').createOutputParameter, + createActivitiIn = require('../CreateHelper').createActivitiIn, + createActivitiOut = require('../CreateHelper').createActivitiOut, + createActivitiInWithBusinessKey = require('../CreateHelper').createActivitiInWithBusinessKey, + createActivitiExecutionListenerScript = require('../CreateHelper').createActivitiExecutionListenerScript, + createActivitiFieldInjection = require('../CreateHelper').createActivitiFieldInjection; + +var forEach = require('lodash/forEach'); + +var ACTIVITI_SERVICE_TASK_LIKE = [ + 'activiti:class', + 'activiti:delegateExpression', + 'activiti:expression' +]; + +/** + * A handler that changes the modeling template of a BPMN element. + */ +function ChangeElementTemplateHandler(modeling, commandStack, bpmnFactory) { + + function getOrCreateExtensionElements(element) { + + var bo = element.businessObject; + + var extensionElements = bo.extensionElements; + + // add extension elements + if (!extensionElements) { + extensionElements = bpmnFactory.create('bpmn:ExtensionElements', { + values: [] + }); + + modeling.updateProperties(element, { + extensionElements: extensionElements + }); + } + + return extensionElements; + } + + function updateModelerTemplate(element, newTemplate) { + modeling.updateProperties(element, { + 'activiti:modelerTemplate': newTemplate && newTemplate.id + }); + } + + function updateIoMappings(element, newTemplate, context) { + + var newMappings = createInputOutputMappings(newTemplate, bpmnFactory), + oldMappings; + + if (!newMappings) { + return; + } + + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: { inputOutput: newMappings } + }); + } else { + context = getOrCreateExtensionElements(element); + oldMappings = findExtension(element, 'activiti:InputOutput'); + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: context, + propertyName: 'values', + objectsToAdd: [ newMappings ], + objectsToRemove: oldMappings ? [ oldMappings ] : [] + }); + } + } + + function updateActivitiField(element, newTemplate, context) { + + var newMappings = createActivitiFieldInjections(newTemplate, bpmnFactory), + oldMappings; + + if (!newMappings) { + return; + } + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: { field: newMappings } + }); + } else { + context = getOrCreateExtensionElements(element); + oldMappings = findExtensions(element, ['activiti:Field']); + + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: context, + propertyName: 'values', + objectsToAdd: newMappings, + objectsToRemove: oldMappings ? oldMappings : [] + }); + } + } + + + function updateActivitiProperties(element, newTemplate, context) { + + var newProperties = createActivitiProperties(newTemplate, bpmnFactory), + oldProperties; + + if (!newProperties) { + return; + } + + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: { properties: newProperties } + }); + } else { + context = getOrCreateExtensionElements(element); + oldProperties = findExtension(element, 'activiti:Properties'); + + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: context, + propertyName: 'values', + objectsToAdd: [ newProperties ], + objectsToRemove: oldProperties ? [ oldProperties ] : [] + }); + } + } + + function updateProperties(element, newTemplate, context) { + + var newProperties = createBpmnPropertyUpdates(newTemplate, bpmnFactory); + + var newPropertiesCount = Object.keys(newProperties).length; + + if (!newPropertiesCount) { + return; + } + + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: newProperties + }); + } else { + modeling.updateProperties(element, newProperties); + } + } + + function updateInOut(element, newTemplate, context) { + + var newInOut = createActivitiInOut(newTemplate, bpmnFactory), + oldInOut; + + if (!newInOut) { + return; + } + + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: { inout: newInOut } + }); + } else { + context = getOrCreateExtensionElements(element); + oldInOut = findExtensions(context, [ 'activiti:In', 'activiti:Out' ]); + + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: context, + propertyName: 'values', + objectsToAdd: newInOut, + objectsToRemove: oldInOut + }); + } + } + + function updateExecutionListener(element, newTemplate, context) { + + var newExecutionListeners = createActivitiExecutionListeners(newTemplate, bpmnFactory), + oldExecutionsListeners; + + if (!newExecutionListeners.length) { + return; + } + + if (context) { + commandStack.execute('properties-panel.update-businessobject', { + element: element, + businessObject: context, + properties: { executionListener: newExecutionListeners } + }); + } else { + context = getOrCreateExtensionElements(element); + oldExecutionsListeners = findExtensions(context, [ 'activiti:ExecutionListener' ]); + + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: context, + propertyName: 'values', + objectsToAdd: newExecutionListeners, + objectsToRemove: oldExecutionsListeners + }); + } + } + + /** + * Update / recreate a scoped element. + * + * @param {djs.model.Base} element the diagram parent element + * @param {String} scopeName name of the scope, i.e. activiti:Connector + * @param {Object} scopeDefinition + */ + function updateScopeElements(element, scopeName, scopeDefinition) { + + var scopeElement = bpmnFactory.create(scopeName); + + // update activiti:inputOutput + updateIoMappings(element, scopeDefinition, scopeElement); + + // update activiti:field + updateActivitiField(element, scopeDefinition, scopeElement); + + // update activiti:properties + updateActivitiProperties(element, scopeDefinition, scopeElement); + + // update other properties (bpmn:condition, activiti:async, ...) + updateProperties(element, scopeDefinition, scopeElement); + + // update activiti:in and activiti:out + updateInOut(element, scopeDefinition, scopeElement); + + // update activiti:executionListener + updateExecutionListener(element, scopeDefinition, scopeElement); + + var extensionElements = getOrCreateExtensionElements(element); + var oldScope = findExtension(extensionElements, scopeName); + + commandStack.execute('properties-panel.update-businessobject-list', { + element: element, + currentObject: extensionElements, + propertyName: 'values', + objectsToAdd: [ scopeElement ], + objectsToRemove: oldScope ? [ oldScope ] : [] + }); + } + + /** + * Compose an element template change action, updating all + * necessary underlying properties. + * + * @param {Object} context + * @param {Object} context.element + * @param {Object} context.oldTemplate + * @param {Object} context.newTemplate + */ + this.preExecute = function(context) { + + var element = context.element, + newTemplate = context.newTemplate; + + // update activiti:modelerTemplate attribute + updateModelerTemplate(element, newTemplate); + + if (newTemplate) { + + // update activiti:inputOutput + updateIoMappings(element, newTemplate); + + // update activiti:field + updateActivitiField(element, newTemplate); + + // update activiti:properties + updateActivitiProperties(element, newTemplate); + + // update other properties (bpmn:condition, activiti:async, ...) + updateProperties(element, newTemplate); + + // update activiti:in and activiti:out + updateInOut(element, newTemplate); + + // update activiti:executionListener + updateExecutionListener(element, newTemplate); + + // loop on scopes properties + forEach(newTemplate.scopes, function(scopeDefinition, scopeName) { + updateScopeElements(element, scopeName, scopeDefinition); + }); + + } + }; +} + +ChangeElementTemplateHandler.$inject = [ 'modeling', 'commandStack', 'bpmnFactory' ]; + +module.exports = ChangeElementTemplateHandler; + + + +// helpers ///////////////////////////// + +function createBpmnPropertyUpdates(template, bpmnFactory) { + + var propertyUpdates = {}; + + template.properties.forEach(function(p) { + + var binding = p.binding, + bindingTarget = binding.name, + propertyValue; + + if (binding.type === 'property') { + + if (bindingTarget === 'conditionExpression') { + propertyValue = bpmnFactory.create('bpmn:FormalExpression', { + body: p.value, + language: binding.scriptFormat + }); + } else { + propertyValue = p.value; + } + + // assigning activiti:async to true|false + // assigning bpmn:conditionExpression to { $type: 'bpmn:FormalExpression', ... } + propertyUpdates[bindingTarget] = propertyValue; + + // make sure we unset other "implementation types" + // when applying a activiti:class template onto a preconfigured + // activiti:delegateExpression element + if (ACTIVITI_SERVICE_TASK_LIKE.indexOf(bindingTarget) !== -1) { + ACTIVITI_SERVICE_TASK_LIKE.forEach(function(prop) { + if (prop !== bindingTarget) { + propertyUpdates[prop] = undefined; + } + }); + } + } + }); + + return propertyUpdates; +} + +function createActivitiFieldInjections(template, bpmnFactory) { + var injections = []; + + template.properties.forEach(function(p) { + var binding = p.binding, + bindingType = binding.type; + if (bindingType === 'activiti:field') { + injections.push(createActivitiFieldInjection( + binding, p.value, bpmnFactory + )); + } + }); + + if (injections.length) { + return injections; + } +} + +function createActivitiProperties(template, bpmnFactory) { + + var properties = []; + + template.properties.forEach(function(p) { + var binding = p.binding, + bindingType = binding.type; + + if (bindingType === 'activiti:property') { + properties.push(createActivitiProperty( + binding, p.value, bpmnFactory + )); + } + }); + + if (properties.length) { + return bpmnFactory.create('activiti:Properties', { + values: properties + }); + } +} + +function createInputOutputMappings(template, bpmnFactory) { + + var inputParameters = [], + outputParameters = []; + + template.properties.forEach(function(p) { + var binding = p.binding, + bindingType = binding.type; + + if (bindingType === 'activiti:inputParameter') { + inputParameters.push(createInputParameter( + binding, p.value, bpmnFactory + )); + } + + if (bindingType === 'activiti:outputParameter') { + outputParameters.push(createOutputParameter( + binding, p.value, bpmnFactory + )); + } + }); + + // do we need to create new ioMappings (?) + if (outputParameters.length || inputParameters.length) { + return bpmnFactory.create('activiti:InputOutput', { + inputParameters: inputParameters, + outputParameters: outputParameters + }); + } +} + +function createActivitiInOut(template, bpmnFactory) { + + var inOuts = []; + + template.properties.forEach(function(p) { + var binding = p.binding, + bindingType = binding.type; + + if (bindingType === 'activiti:in') { + inOuts.push(createActivitiIn( + binding, p.value, bpmnFactory + )); + } else + if (bindingType === 'activiti:out') { + inOuts.push(createActivitiOut( + binding, p.value, bpmnFactory + )); + } else + if (bindingType === 'activiti:in:businessKey') { + inOuts.push(createActivitiInWithBusinessKey( + binding, p.value, bpmnFactory + )); + } + }); + + return inOuts; +} + + +function createActivitiExecutionListeners(template, bpmnFactory) { + + var executionListener = []; + + template.properties.forEach(function(p) { + var binding = p.binding, + bindingType = binding.type; + + if (bindingType === 'activiti:executionListener') { + executionListener.push(createActivitiExecutionListenerScript( + binding, p.value, bpmnFactory + )); + } + }); + + return executionListener; +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/index.js new file mode 100644 index 00000000..df053d6e --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/cmd/index.js @@ -0,0 +1,46 @@ +'use strict'; + +var ChangeElementTemplateHandler = require('./ChangeElementTemplateHandler'); + +var getTemplate = require('../Helper').getTemplate, + getDefaultTemplate = require('../Helper').getDefaultTemplate; + +function registerHandlers(commandStack, elementTemplates, eventBus, elementRegistry) { + commandStack.registerHandler( + 'propertiesPanel.activiti.changeTemplate', + ChangeElementTemplateHandler + ); + + // apply default element templates on shape creation + eventBus.on([ 'commandStack.shape.create.postExecuted' ], function(context) { + applyDefaultTemplate(context.context.shape, elementTemplates, commandStack); + }); + + // apply default element templates on connection creation + eventBus.on([ 'commandStack.connection.create.postExecuted' ], function(context) { + applyDefaultTemplate(context.context.connection, elementTemplates, commandStack); + }); +} + +registerHandlers.$inject = [ 'commandStack', 'elementTemplates', 'eventBus', 'elementRegistry' ]; + + +module.exports = { + __init__: [ registerHandlers ] +}; + + +function applyDefaultTemplate(element, elementTemplates, commandStack) { + + if (!getTemplate(element, elementTemplates) + && getDefaultTemplate(element, elementTemplates)) { + + var command = 'propertiesPanel.activiti.changeTemplate'; + var commandContext = { + element: element, + newTemplate: getDefaultTemplate(element, elementTemplates) + }; + + commandStack.execute(command, commandContext); + } +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/index.js new file mode 100644 index 00000000..ccfb428c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/index.js @@ -0,0 +1,13 @@ +module.exports = { + __depends__: [ + require('./cmd/index'), + require('diagram-js/lib/i18n/translate').default + ], + __init__: [ + 'customElementsPropertiesActivator', + 'elementTemplatesLoader' + ], + customElementsPropertiesActivator: [ 'type', require('./CustomElementsPropertiesActivator') ], + elementTemplates: [ 'type', require('./ElementTemplates') ], + elementTemplatesLoader: [ 'type', require('./ElementTemplatesLoader') ] +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/ChooserProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/ChooserProps.js new file mode 100644 index 00000000..a0aa3367 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/ChooserProps.js @@ -0,0 +1,151 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + is = require('bpmn-js/lib/util/ModelUtil').is, + getTemplate = require('../Helper').getTemplate, + getTemplateId = require('../Helper').getTemplateId; + +var find = require('lodash/find'); + +var TEMPLATE_ATTR = require('../Helper').TEMPLATE_ATTR; + +function isAny(element, types) { + return types.reduce(function(result, type) { + return result || is(element, type); + }, false); +} + + +module.exports = function(group, element, elementTemplates, translate) { + + var options = getTemplateOptions(element, elementTemplates, translate); + + if (options.length === 1 && !options[0].isDefault) { + return; + } + + // select element template (via dropdown) + group.entries.push(entryFactory.selectBox({ + id: 'elementTemplate-chooser', + label: translate('Element Template'), + modelProperty: 'activiti:modelerTemplate', + selectOptions: options, + set: function(element, properties) { + return applyTemplate(element, properties[TEMPLATE_ATTR], elementTemplates); + }, + disabled: function() { + var template = getTemplate(element, elementTemplates); + + return template && isDefaultTemplate(template); + } + })); + +}; + + +// helpers ////////////////////////////////////// + +function applyTemplate(element, newTemplateId, elementTemplates) { + + // cleanup + // clear input output mappings + // undo changes to properties defined in template + + // re-establish + // set input output mappings + // apply changes to properties as defined in new template + + var oldTemplate = getTemplate(element, elementTemplates), + newTemplate = elementTemplates.get(newTemplateId); + + if (oldTemplate === newTemplate) { + return; + } + + return { + cmd: 'propertiesPanel.activiti.changeTemplate', + context: { + element: element, + oldTemplate: oldTemplate, + newTemplate: newTemplate + } + }; +} + +function getTemplateOptions(element, elementTemplates, translate) { + + var currentTemplateId = getTemplateId(element); + + var emptyOption = { + name: '', + value: '' + }; + + var allOptions = elementTemplates.getAll().reduce(function(templates, t) { + if (!isAny(element, t.appliesTo)) { + return templates; + } + + return templates.concat({ + name: translate(t.name), + value: t.id, + isDefault: t.isDefault + }); + }, [ emptyOption ]); + + + var defaultOption = find(allOptions, function(option) { + return isDefaultTemplate(option); + }); + + var currentOption = find(allOptions, function(option) { + return option.value === currentTemplateId; + }); + + if (currentTemplateId && !currentOption) { + currentOption = unknownTemplate(currentTemplateId, translate); + + allOptions.push(currentOption); + } + + if (!defaultOption) { + + // return all options, including empty + // and optionally unknownTemplate option + return allOptions; + } + + // special limited handling for + // default options + + var options = []; + + // current template not set + if (!currentTemplateId) { + options.push({ + name: '', + value: '' + }); + } + + // current template not default + if (currentOption && currentOption !== defaultOption) { + options.push(currentOption); + } + + options.push(defaultOption); + + // [ (empty), (current), defaultOption ] + return options; +} + +function unknownTemplate(templateId, translate) { + return { + name: translate('[unknown template: {templateId}]', { templateId: templateId }), + value: templateId + }; +} + +function isDefaultTemplate(elementTemplate) { + return elementTemplate.isDefault; +} \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/CustomProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/CustomProps.js new file mode 100644 index 00000000..d1bae37b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/parts/CustomProps.js @@ -0,0 +1,770 @@ +'use strict'; + +var assign = require('lodash/assign'); + +var entryFactory = require('../../../../factory/EntryFactory'), + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + getTemplate = require('../Helper').getTemplate, + cmdHelper = require('../../../../helper/CmdHelper'), + elementHelper = require('../../../../helper/ElementHelper'); + +var findExtension = require('../Helper').findExtension, + findExtensions = require('../Helper').findExtensions, + findInputParameter = require('../Helper').findInputParameter, + findOutputParameter = require('../Helper').findOutputParameter, + findActivitiProperty = require('../Helper').findActivitiProperty, + findActivitiInOut = require('../Helper').findActivitiInOut; + +var createActivitiProperty = require('../CreateHelper').createActivitiProperty, + createInputParameter = require('../CreateHelper').createInputParameter, + createOutputParameter = require('../CreateHelper').createOutputParameter, + createActivitiIn = require('../CreateHelper').createActivitiIn, + createActivitiOut = require('../CreateHelper').createActivitiOut, + createActivitiInWithBusinessKey = require('../CreateHelper').createActivitiInWithBusinessKey, + createActivitiFieldInjection = require('../CreateHelper').createActivitiFieldInjection; + +var ACTIVITI_PROPERTY_TYPE = 'activiti:property', + ACTIVITI_INPUT_PARAMETER_TYPE = 'activiti:inputParameter', + ACTIVITI_OUTPUT_PARAMETER_TYPE = 'activiti:outputParameter', + ACTIVITI_IN_TYPE = 'activiti:in', + ACTIVITI_OUT_TYPE = 'activiti:out', + ACTIVITI_IN_BUSINESS_KEY_TYPE = 'activiti:in:businessKey', + ACTIVITI_EXECUTION_LISTENER_TYPE = 'activiti:executionListener', + ACTIVITI_FIELD = 'activiti:field'; + +var BASIC_MODDLE_TYPES = [ + 'Boolean', + 'Integer', + 'String' +]; + +var EXTENSION_BINDING_TYPES = [ + ACTIVITI_PROPERTY_TYPE, + ACTIVITI_INPUT_PARAMETER_TYPE, + ACTIVITI_OUTPUT_PARAMETER_TYPE, + ACTIVITI_IN_TYPE, + ACTIVITI_OUT_TYPE, + ACTIVITI_IN_BUSINESS_KEY_TYPE, + ACTIVITI_FIELD +]; + +var IO_BINDING_TYPES = [ + ACTIVITI_INPUT_PARAMETER_TYPE, + ACTIVITI_OUTPUT_PARAMETER_TYPE +]; + +var IN_OUT_BINDING_TYPES = [ + ACTIVITI_IN_TYPE, + ACTIVITI_OUT_TYPE, + ACTIVITI_IN_BUSINESS_KEY_TYPE +]; + +/** + * Injects custom properties into the given group. + * + * @param {djs.model.Base} element + * @param {ElementTemplates} elementTemplates + * @param {BpmnFactory} bpmnFactory + * @param {Function} translate + */ +module.exports = function(element, elementTemplates, bpmnFactory, translate) { + + var template = getTemplate(element, elementTemplates); + + if (!template) { + return []; + } + + var renderCustomField = function(id, p, idx) { + var propertyType = p.type; + + var entryOptions = { + id: id, + description: p.description, + label: p.label ? translate(p.label) : p.label, + modelProperty: id, + get: propertyGetter(id, p), + set: propertySetter(id, p, bpmnFactory), + validate: propertyValidator(id, p, translate) + }; + + var entry; + + if (propertyType === 'Boolean') { + entry = entryFactory.checkbox(entryOptions); + } + + if (propertyType === 'String') { + entry = entryFactory.textField(entryOptions); + } + + if (propertyType === 'Text') { + entry = entryFactory.textBox(entryOptions); + } + + if (propertyType === 'Dropdown') { + entryOptions.selectOptions = p.choices; + + entry = entryFactory.selectBox(entryOptions); + } + + return entry; + }; + + var groups = []; + var id, entry; + + var customFieldsGroup = { + id: 'customField', + label: translate('Custom Fields'), + entries: [] + }; + template.properties.forEach(function(p, idx) { + + id = 'custom-' + template.id + '-' + idx; + + entry = renderCustomField(id, p, idx); + if (entry) { + customFieldsGroup.entries.push(entry); + } + }); + if (customFieldsGroup.entries.length > 0) { + groups.push(customFieldsGroup); + } + + if (template.scopes) { + for (var scopeName in template.scopes) { + + var scope = template.scopes[scopeName]; + var idScopeName = scopeName.replace(/:/g, '_'); + + var customScopeFieldsGroup = { + id: 'customField-' + idScopeName, + label: translate('Custom Fields for scope: ') + scopeName, + entries: [] + }; + + scope.properties.forEach(function(p, idx) { + + var propertyId = 'custom-' + template.id + '-' + idScopeName + '-' + idx; + + var scopedProperty = propertyWithScope(p, scopeName); + + entry = renderCustomField(propertyId, scopedProperty, idx); + if (entry) { + customScopeFieldsGroup.entries.push(entry); + } + }); + + if (customScopeFieldsGroup.entries.length > 0) { + groups.push(customScopeFieldsGroup); + } + } + } + + return groups; +}; + + +// getters, setters and validators /////////////// + + +/** + * Return a getter that retrieves the given property. + * + * @param {String} name + * @param {PropertyDescriptor} property + * + * @return {Function} + */ +function propertyGetter(name, property) { + + /* getter */ + return function get(element) { + var value = getPropertyValue(element, property); + + return objectWithKey(name, value); + }; +} + +/** + * Return a setter that updates the given property. + * + * @param {String} name + * @param {PropertyDescriptor} property + * @param {BpmnFactory} bpmnFactory + * + * @return {Function} + */ +function propertySetter(name, property, bpmnFactory) { + + /* setter */ + return function set(element, values) { + + var value = values[name]; + + return setPropertyValue(element, property, value, bpmnFactory); + }; +} + +/** + * Return a validator that ensures the property is ok. + * + * @param {String} name + * @param {PropertyDescriptor} property + * @param {Function} translate + * + * @return {Function} + */ +function propertyValidator(name, property, translate) { + + /* validator */ + return function validate(element, values) { + var value = values[name]; + + var error = validateValue(value, property, translate); + + if (error) { + return objectWithKey(name, error); + } + }; +} + + +// get, set and validate helpers /////////////////// + +/** + * Return the value of the specified property descriptor, + * on the passed diagram element. + * + * @param {djs.model.Base} element + * @param {PropertyDescriptor} property + * + * @return {Any} + */ +function getPropertyValue(element, property) { + + var bo = getBusinessObject(element); + + var binding = property.binding, + scope = property.scope; + + var bindingType = binding.type, + bindingName = binding.name; + + var propertyValue = property.value || ''; + + if (scope) { + bo = findExtension(bo, scope.name); + if (!bo) { + return propertyValue; + } + } + + // property + if (bindingType === 'property') { + + var value = bo.get(bindingName); + + if (bindingName === 'conditionExpression') { + if (value) { + return value.body; + } else { + // return defined default + return propertyValue; + } + } else { + // return value; default to defined default + return typeof value !== 'undefined' ? value : propertyValue; + } + } + + var activitiProperties, + activitiProperty; + + if (bindingType === ACTIVITI_PROPERTY_TYPE) { + if (scope) { + activitiProperties = bo.get('properties'); + } else { + activitiProperties = findExtension(bo, 'activiti:Properties'); + } + + if (activitiProperties) { + activitiProperty = findActivitiProperty(activitiProperties, binding); + + if (activitiProperty) { + return activitiProperty.value; + } + } + + return propertyValue; + } + + var inputOutput, + ioParameter; + + if (IO_BINDING_TYPES.indexOf(bindingType) !== -1) { + + if (scope) { + inputOutput = bo.get('inputOutput'); + } else { + inputOutput = findExtension(bo, 'activiti:InputOutput'); + } + + if (!inputOutput) { + // ioParameter cannot exist yet, return property value + return propertyValue; + } + } + + // activiti input parameter + if (bindingType === ACTIVITI_INPUT_PARAMETER_TYPE) { + ioParameter = findInputParameter(inputOutput, binding); + + if (ioParameter) { + if (binding.scriptFormat) { + if (ioParameter.definition) { + return ioParameter.definition.value; + } + } else { + return ioParameter.value || ''; + } + } + + return propertyValue; + } + + // activiti output parameter + if (binding.type === ACTIVITI_OUTPUT_PARAMETER_TYPE) { + ioParameter = findOutputParameter(inputOutput, binding); + + if (ioParameter) { + return ioParameter.name; + } + + return propertyValue; + } + + + var ioElement; + + if (IN_OUT_BINDING_TYPES.indexOf(bindingType) != -1) { + ioElement = findActivitiInOut(bo, binding); + + if (ioElement) { + if (bindingType === ACTIVITI_IN_BUSINESS_KEY_TYPE) { + return ioElement.businessKey; + } else + if (bindingType === ACTIVITI_OUT_TYPE) { + return ioElement.target; + } else + if (bindingType === ACTIVITI_IN_TYPE) { + return ioElement[binding.expression ? 'sourceExpression' : 'source']; + } + } + + return propertyValue; + } + + if (bindingType === ACTIVITI_EXECUTION_LISTENER_TYPE) { + var executionListener; + if (scope) { + executionListener = bo.get('executionListener'); + } else { + executionListener = findExtension(bo, 'activiti:ExecutionListener'); + } + + return executionListener.script.value; + } + + var fieldInjection; + if (ACTIVITI_FIELD === bindingType) { + var fieldInjections = findExtensions(bo, [ 'activiti:Field' ]); + fieldInjections.forEach(function(item) { + if (item.name === binding.name) { + fieldInjection = item; + } + }); + if (fieldInjection) { + return fieldInjection.string || fieldInjection.expression; + } else { + return ''; + } + } + + throw unknownPropertyBinding(property); +} + +module.exports.getPropertyValue = getPropertyValue; + + +/** + * Return an update operation that changes the diagram + * element's custom property to the given value. + * + * The response of this method will be processed via + * {@link PropertiesPanel#applyChanges}. + * + * @param {djs.model.Base} element + * @param {PropertyDescriptor} property + * @param {String} value + * @param {BpmnFactory} bpmnFactory + * + * @return {Object|Array} results to be processed + */ +function setPropertyValue(element, property, value, bpmnFactory) { + var bo = getBusinessObject(element); + + var binding = property.binding, + scope = property.scope; + + var bindingType = binding.type, + bindingName = binding.name; + + var propertyValue; + + var updates = []; + + var extensionElements; + + if (EXTENSION_BINDING_TYPES.indexOf(bindingType) !== -1) { + extensionElements = bo.get('extensionElements'); + + // create extension elements, if they do not exist (yet) + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', null, element, bpmnFactory); + + updates.push(cmdHelper.updateBusinessObject( + element, bo, objectWithKey('extensionElements', extensionElements) + )); + } + } + + if (scope) { + bo = findExtension(bo, scope.name); + if (!bo) { + bo = elementHelper.createElement(scope.name, null, element, bpmnFactory); + + updates.push(cmdHelper.addElementsTolist( + bo, extensionElements, 'values', [ bo ] + )); + } + } + + // property + if (bindingType === 'property') { + + if (bindingName === 'conditionExpression') { + + propertyValue = elementHelper.createElement('bpmn:FormalExpression', { + body: value, + language: binding.scriptFormat + }, bo, bpmnFactory); + } else { + + var moddlePropertyDescriptor = bo.$descriptor.propertiesByName[bindingName]; + + var moddleType = moddlePropertyDescriptor.type; + + // make sure we only update String, Integer, Real and + // Boolean properties (do not accidentally override complex objects...) + if (BASIC_MODDLE_TYPES.indexOf(moddleType) === -1) { + throw new Error('cannot set moddle type <' + moddleType + '>'); + } + + if (moddleType === 'Boolean') { + propertyValue = !!value; + } else + if (moddleType === 'Integer') { + propertyValue = parseInt(value, 10); + + if (isNaN(propertyValue)) { + // do not write NaN value + propertyValue = undefined; + } + } else { + propertyValue = value; + } + } + + if (propertyValue !== undefined) { + updates.push(cmdHelper.updateBusinessObject( + element, bo, objectWithKey(bindingName, propertyValue) + )); + } + } + + // activiti:property + var activitiProperties, + existingActivitiProperty, + newActivitiProperty; + + if (bindingType === ACTIVITI_PROPERTY_TYPE) { + + if (scope) { + activitiProperties = bo.get('properties'); + } else { + activitiProperties = findExtension(extensionElements, 'activiti:Properties'); + } + + if (!activitiProperties) { + activitiProperties = elementHelper.createElement('activiti:Properties', null, bo, bpmnFactory); + + if (scope) { + updates.push(cmdHelper.updateBusinessObject( + element, bo, { properties: activitiProperties } + )); + } + else { + updates.push(cmdHelper.addElementsTolist( + element, extensionElements, 'values', [ activitiProperties ] + )); + } + } + + existingActivitiProperty = findActivitiProperty(activitiProperties, binding); + + newActivitiProperty = createActivitiProperty(binding, value, bpmnFactory); + + updates.push(cmdHelper.addAndRemoveElementsFromList( + element, + activitiProperties, + 'values', + null, + [ newActivitiProperty ], + existingActivitiProperty ? [ existingActivitiProperty ] : [] + )); + } + + // activiti:inputParameter + // activiti:outputParameter + var inputOutput, + existingIoParameter, + newIoParameter; + + if (IO_BINDING_TYPES.indexOf(bindingType) !== -1) { + + if (scope) { + inputOutput = bo.get('inputOutput'); + } else { + inputOutput = findExtension(extensionElements, 'activiti:InputOutput'); + } + + // create inputOutput element, if it do not exist (yet) + if (!inputOutput) { + inputOutput = elementHelper.createElement('activiti:InputOutput', null, bo, bpmnFactory); + + if (scope) { + updates.push(cmdHelper.updateBusinessObject( + element, bo, { inputOutput: inputOutput } + )); + } + else { + updates.push(cmdHelper.addElementsTolist( + element, extensionElements, 'values', inputOutput + )); + } + } + } + + if (bindingType === ACTIVITI_INPUT_PARAMETER_TYPE) { + + existingIoParameter = findInputParameter(inputOutput, binding); + + newIoParameter = createInputParameter(binding, value, bpmnFactory); + + updates.push(cmdHelper.addAndRemoveElementsFromList( + element, + inputOutput, + 'inputParameters', + null, + [ newIoParameter ], + existingIoParameter ? [ existingIoParameter ] : [] + )); + } + + if (bindingType === ACTIVITI_OUTPUT_PARAMETER_TYPE) { + + existingIoParameter = findOutputParameter(inputOutput, binding); + + newIoParameter = createOutputParameter(binding, value, bpmnFactory); + + updates.push(cmdHelper.addAndRemoveElementsFromList( + element, + inputOutput, + 'outputParameters', + null, + [ newIoParameter ], + existingIoParameter ? [ existingIoParameter ] : [] + )); + } + + + // activiti:in + // activiti:out + // activiti:in:businessKey + var existingInOut, + newInOut; + + if (IN_OUT_BINDING_TYPES.indexOf(bindingType) !== -1) { + + existingInOut = findActivitiInOut(bo, binding); + + if (bindingType === ACTIVITI_IN_TYPE) { + newInOut = createActivitiIn(binding, value, bpmnFactory); + } else + if (bindingType === ACTIVITI_OUT_TYPE) { + newInOut = createActivitiOut(binding, value, bpmnFactory); + } else { + newInOut = createActivitiInWithBusinessKey(binding, value, bpmnFactory); + } + + updates.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + null, + [ newInOut ], + existingInOut ? [ existingInOut ] : [] + )); + } + + if (bindingType === ACTIVITI_FIELD) { + var existingFieldInjections = findExtensions(bo, [ 'activiti:Field' ]); + var newFieldInjections = []; + + if (existingFieldInjections.length > 0) { + existingFieldInjections.forEach(function(item) { + if (item.name === binding.name) { + newFieldInjections.push(createActivitiFieldInjection(binding, value, bpmnFactory)); + } else { + newFieldInjections.push(item); + } + }); + } else { + newFieldInjections.push(createActivitiFieldInjection(binding, value, bpmnFactory)); + } + + updates.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + null, + newFieldInjections, + existingFieldInjections ? existingFieldInjections : [] + )); + } + + if (updates.length) { + return updates; + } + + // quick warning for better debugging + console.warn('no update', element, property, value); +} + +module.exports.setPropertyValue = setPropertyValue; + +/** + * Validate value of a given property. + * + * @param {String} value + * @param {PropertyDescriptor} property + * @param {Function} translate + * + * @return {Object} with validation errors + */ +function validateValue(value, property, translate) { + + var constraints = property.constraints || {}; + + if (constraints.notEmpty && isEmpty(value)) { + return translate('Must not be empty'); + } + + if (constraints.maxLength && value.length > constraints.maxLength) { + return translate('Must have max length {length}', { length: constraints.maxLength }); + } + + if (constraints.minLength && value.length < constraints.minLength) { + return translate('Must have min length {length}', { length: constraints.minLength }); + } + + var pattern = constraints.pattern, + message; + + if (pattern) { + + if (typeof pattern !== 'string') { + message = pattern.message; + pattern = pattern.value; + } + + if (!matchesPattern(value, pattern)) { + return message || translate('Must match pattern {pattern}', { pattern: pattern }); + } + } +} + + +// misc helpers /////////////////////////////// + +function propertyWithScope(property, scopeName) { + if (!scopeName) { + return property; + } + + return assign({}, property, { + scope: { + name: scopeName + } + }); +} + +/** + * Return an object with a single key -> value association. + * + * @param {String} key + * @param {Any} value + * + * @return {Object} + */ +function objectWithKey(key, value) { + var obj = {}; + + obj[key] = value; + + return obj; +} + +/** + * Does the given string match the specified pattern? + * + * @param {String} str + * @param {String} pattern + * + * @return {Boolean} + */ +function matchesPattern(str, pattern) { + var regexp = new RegExp(pattern); + + return regexp.test(str); +} + +function isEmpty(str) { + return !str || /^\s*$/.test(str); +} + +/** + * Create a new {@link Error} indicating an unknown + * property binding. + * + * @param {PropertyDescriptor} property + * + * @return {Error} + */ +function unknownPropertyBinding(property) { + var binding = property.binding; + + return new Error('unknown binding: <' + binding.type + '>'); +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/util/validate.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/util/validate.js new file mode 100644 index 00000000..521924bd --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/element-templates/util/validate.js @@ -0,0 +1,16 @@ +'use strict'; + +var Validator = require('../Validator'); + +/** + * Validate the given template descriptors and + * return a list of errors. + * + * @param {Array} descriptors + * + * @return {Array} + */ +module.exports = function validate(descriptors) { + + return new Validator().addAll(descriptors).getErrors(); +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/index.js new file mode 100644 index 00000000..de4843c9 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/index.js @@ -0,0 +1,9 @@ +module.exports = { + __depends__: [ + require('./element-templates/index'), + require('diagram-js/lib/i18n/translate').default + ], + __init__: [ 'propertiesProvider' ], + propertiesProvider: [ 'type', require('./ActivitiPropertiesProvider') ] +}; + diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/AsynchronousContinuationProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/AsynchronousContinuationProps.js new file mode 100644 index 00000000..4d9606b0 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/AsynchronousContinuationProps.js @@ -0,0 +1,16 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is, + asyncContinuation = require('./implementation/AsyncContinuation'); + +module.exports = function(group, element, bpmnFactory, translate) { + + if (is(element, 'activiti:AsyncCapable')) { + + group.entries = group.entries.concat(asyncContinuation(element, bpmnFactory, { + getBusinessObject: getBusinessObject + }, translate)); + + } +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CallActivityProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CallActivityProps.js new file mode 100644 index 00000000..f8684385 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CallActivityProps.js @@ -0,0 +1,90 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is; + +var entryFactory = require('../../../factory/EntryFactory'); + +var callable = require('./implementation/Callable'); + +var cmdHelper = require('../../../helper/CmdHelper'); + +var flattenDeep = require('lodash/flattenDeep'); +var assign = require('lodash/assign'); + +function getCallableType(element) { + var bo = getBusinessObject(element); + + var boCalledElement = bo.get('calledElement'), + boCaseRef = bo.get('activiti:caseRef'); + + var callActivityType = ''; + if (typeof boCalledElement !== 'undefined') { + callActivityType = 'bpmn'; + } else + + if (typeof boCaseRef !== 'undefined') { + callActivityType = 'cmmn'; + } + + return callActivityType; +} + +var DEFAULT_PROPS = { + calledElement: undefined, + 'activiti:calledElementBinding': 'latest', + 'activiti:calledElementVersion': undefined, + 'activiti:calledElementTenantId': undefined, + 'activiti:variableMappingClass' : undefined, + 'activiti:variableMappingDelegateExpression' : undefined, + 'activiti:caseRef': undefined, + 'activiti:caseBinding': 'latest', + 'activiti:caseVersion': undefined, + 'activiti:caseTenantId': undefined +}; + +module.exports = function(group, element, bpmnFactory, translate) { + + if (!is(element, 'activiti:CallActivity')) { + return; + } + + group.entries.push(entryFactory.selectBox({ + id : 'callActivity', + label: translate('CallActivity Type'), + selectOptions: [ + { name: 'BPMN', value: 'bpmn' }, + { name: 'CMMN', value: 'cmmn' } + ], + emptyParameter: true, + modelProperty: 'callActivityType', + + get: function(element, node) { + return { + callActivityType: getCallableType(element) + }; + }, + + set: function(element, values, node) { + var type = values.callActivityType; + + var props = assign({}, DEFAULT_PROPS); + + if (type === 'bpmn') { + props.calledElement = ''; + } + else if (type === 'cmmn') { + props['activiti:caseRef'] = ''; + } + + return cmdHelper.updateProperties(element, props); + } + + })); + + group.entries.push(callable(element, bpmnFactory, { + getCallableType: getCallableType + }, translate)); + + group.entries = flattenDeep(group.entries); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CandidateStarterProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CandidateStarterProps.js new file mode 100644 index 00000000..bd3397d6 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/CandidateStarterProps.js @@ -0,0 +1,27 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var candidateStarter = require('./implementation/CandidateStarter'); + +module.exports = function(group, element, bpmnFactory, translate) { + var businessObject = getBusinessObject(element); + + if (is(element, 'activiti:Process') || + is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + + group.entries = group.entries.concat(candidateStarter(element, bpmnFactory, { + getBusinessObject: function(element) { + var bo = getBusinessObject(element); + + if (!is(bo, 'bpmn:Participant')) { + return bo; + } + + return bo.get('processRef'); + } + }, translate)); + + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConditionalProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConditionalProps.js new file mode 100644 index 00000000..050d933d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConditionalProps.js @@ -0,0 +1,185 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + isAny = require('bpmn-js/lib/features/modeling/util/ModelingUtil').isAny, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + escapeHTML = require('../../../Utils').escapeHTML, + domQuery = require('min-dom').query, + cmdHelper = require('../../../helper/CmdHelper'), + elementHelper = require('../../../helper/ElementHelper'), + eventDefinitionHelper = require('../../../helper/EventDefinitionHelper'), + scriptImplementation = require('./implementation/Script'); + + +module.exports = function(group, element, bpmnFactory, translate) { + var bo = getBusinessObject(element); + + if (!bo) { + return; + } + + var conditionalEventDefinition = eventDefinitionHelper.getConditionalEventDefinition(element); + + if (!(is(element, 'bpmn:SequenceFlow') && isConditionalSource(element.source)) + && !conditionalEventDefinition) { + return; + } + + var script = scriptImplementation('language', 'body', true, translate); + group.entries.push({ + id: 'condition', + label: translate('Condition'), + html: '' + + ''+ escapeHTML(translate('Condition Type')) + '' + + '' + + '' + + ''+ escapeHTML(translate('Expression')) + '' + + ''+ escapeHTML(translate('Script')) + '' + + '' + + '' + + '' + + '' + + + // expression + '' + + '' + escapeHTML(translate('Expression')) + '' + + '' + + '' + + '' + + 'X' + + '' + + '' + + '' + + script.template + + '' + + '', + + get: function(element, propertyName) { + var conditionalEventDefinition = eventDefinitionHelper.getConditionalEventDefinition(element); + + var conditionExpression = conditionalEventDefinition + ? conditionalEventDefinition.condition + : bo.conditionExpression; + + var values = {}, + conditionType = ''; + + if (conditionExpression) { + var conditionLanguage = conditionExpression.language; + if (typeof conditionLanguage !== 'undefined') { + conditionType = 'script'; + values = script.get(element, conditionExpression); + } else { + conditionType = 'expression'; + values.condition = conditionExpression.get('body'); + } + } + + values.conditionType = conditionType; + + return values; + + }, + + set: function(element, values, containerElement) { + var conditionType = values.conditionType; + var commands = []; + + var conditionProps = { + body: undefined + }; + + if (conditionType === 'script') { + conditionProps = script.set(element, values, containerElement); + } else { + var condition = values.condition; + + conditionProps.body = condition; + } + + var conditionOrConditionExpression; + + if (conditionType) { + conditionOrConditionExpression = elementHelper.createElement( + 'bpmn:FormalExpression', + conditionProps, + conditionalEventDefinition || bo, + bpmnFactory + ); + + var source = element.source; + + // if default-flow, remove default-property from source + if (source && source.businessObject.default === bo) { + commands.push(cmdHelper.updateProperties(source, { 'default': undefined })); + } + } + + var update = conditionalEventDefinition + ? { condition: conditionOrConditionExpression } + : { conditionExpression: conditionOrConditionExpression }; + + commands.push(cmdHelper.updateBusinessObject(element, conditionalEventDefinition || bo, update)); + + return commands; + }, + + validate: function(element, values) { + var validationResult = {}; + + if (!values.condition && values.conditionType === 'expression') { + validationResult.condition = translate('Must provide a value'); + } + else if (values.conditionType === 'script') { + validationResult = script.validate(element, values); + } + + return validationResult; + }, + + isExpression: function(element, inputNode) { + var conditionType = domQuery('select[name=conditionType]', inputNode); + if (conditionType.selectedIndex >= 0) { + return conditionType.options[conditionType.selectedIndex].value === 'expression'; + } + }, + + isScript: function(element, inputNode) { + var conditionType = domQuery('select[name=conditionType]', inputNode); + if (conditionType.selectedIndex >= 0) { + return conditionType.options[conditionType.selectedIndex].value === 'script'; + } + }, + + clear: function(element, inputNode) { + // clear text input + domQuery('input[name=condition]', inputNode).value=''; + + return true; + }, + + canClear: function(element, inputNode) { + var input = domQuery('input[name=condition]', inputNode); + + return input.value !== ''; + }, + + script : script, + + cssClasses: [ 'bpp-textfield' ] + }); +}; + + +// utilities ////////////////////////// + +var CONDITIONAL_SOURCES = [ + 'bpmn:Activity', + 'bpmn:ExclusiveGateway', + 'bpmn:InclusiveGateway', + 'bpmn:ComplexGateway' +]; + +function isConditionalSource(element) { + return isAny(element, CONDITIONAL_SOURCES); +} diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorDetailProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorDetailProps.js new file mode 100644 index 00000000..69eaed9e --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorDetailProps.js @@ -0,0 +1,57 @@ +'use strict'; + +var ImplementationTypeHelper = require('../../../helper/ImplementationTypeHelper'), + InputOutputHelper = require('../../../helper/InputOutputHelper'); + +var entryFactory = require('../../../factory/EntryFactory'), + cmdHelper = require('../../../helper/CmdHelper'); + +function getImplementationType(element) { + return ImplementationTypeHelper.getImplementationType(element); +} + +function getBusinessObject(element) { + return ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element); +} + +function getConnector(bo) { + return InputOutputHelper.getConnector(bo); +} + +function isConnector(element) { + return getImplementationType(element) === 'connector'; +} + +module.exports = function(group, element, bpmnFactory, translate) { + + group.entries.push(entryFactory.textField({ + id: 'connectorId', + label: translate('Connector Id'), + modelProperty: 'connectorId', + + get: function(element, node) { + var bo = getBusinessObject(element); + var connector = bo && getConnector(bo); + var value = connector && connector.get('connectorId'); + return { connectorId: value }; + }, + + set: function(element, values, node) { + var bo = getBusinessObject(element); + var connector = getConnector(bo); + return cmdHelper.updateBusinessObject(element, connector, { + connectorId: values.connectorId || undefined + }); + }, + + validate: function(element, values, node) { + return isConnector(element) && !values.connectorId ? { connectorId: translate('Must provide a value') } : {}; + }, + + hidden: function(element, node) { + return !isConnector(element); + } + + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputParameterProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputParameterProps.js new file mode 100644 index 00000000..966344d7 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputParameterProps.js @@ -0,0 +1,16 @@ +'use strict'; + +var assign = require('lodash/assign'); + +var inputOutputParameter = require('./implementation/InputOutputParameter'); + +module.exports = function(group, element, bpmnFactory, options, translate) { + + options = assign({ + idPrefix: 'connector-', + insideConnector: true + }, options); + + group.entries = group.entries.concat(inputOutputParameter(element, bpmnFactory, options, translate)); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputProps.js new file mode 100644 index 00000000..b24faefb --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ConnectorInputOutputProps.js @@ -0,0 +1,18 @@ +'use strict'; + +var inputOutput = require('./implementation/InputOutput'); + +module.exports = function(group, element, bpmnFactory, translate) { + + var inputOutputEntry = inputOutput(element, bpmnFactory, { + idPrefix: 'connector-', + insideConnector: true + }, translate); + + group.entries = group.entries.concat(inputOutputEntry.entries); + + return { + getSelectedParameter: inputOutputEntry.getSelectedParameter + }; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ErrorEventProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ErrorEventProps.js new file mode 100644 index 00000000..6f69379b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ErrorEventProps.js @@ -0,0 +1,40 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + eventDefinitionHelper = require('../../../helper/EventDefinitionHelper'), + error = require('./implementation/ErrorEventDefinition'); + +var forEach = require('lodash/forEach'); + + +module.exports = function(group, element, bpmnFactory, translate) { + + var errorEvents = [ + 'bpmn:StartEvent', + 'bpmn:BoundaryEvent', + 'bpmn:EndEvent' + ]; + + forEach(errorEvents, function(event) { + if (is(element, event)) { + + var errorEventDefinition = eventDefinitionHelper.getErrorEventDefinition(element); + + if (errorEventDefinition) { + var isCatchingErrorEvent = is(element, 'bpmn:StartEvent') || is (element, 'bpmn:BoundaryEvent'); + + var showErrorCodeVariable = isCatchingErrorEvent, + showErrorMessageVariable = isCatchingErrorEvent; + + error( + group, + element, + bpmnFactory, + errorEventDefinition, + showErrorCodeVariable, + showErrorMessageVariable, + translate); + } + } + }); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ExternalTaskConfigurationProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ExternalTaskConfigurationProps.js new file mode 100644 index 00000000..70d90df3 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ExternalTaskConfigurationProps.js @@ -0,0 +1,40 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var ImplementationTypeHelper = require('../../../helper/ImplementationTypeHelper'); + +var externalTaskPriority = require('./implementation/ExternalTaskPriority'); + +function getServiceTaskLikeBusinessObject(element) { + var bo = ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element); + + // if the element is not a serviceTaskLike element, fetch the normal business object + // This avoids the loss of the process / participant business object + if (!bo) { + bo = getBusinessObject(element); + } + + return bo; +} + +module.exports = function(group, element, bpmnFactory, translate) { + + var bo = getServiceTaskLikeBusinessObject(element); + + if (!bo) { + return; + } + + if (is(bo, 'activiti:TaskPriorized') || (is(bo, 'bpmn:Participant')) && bo.get('processRef')) { + group.entries = group.entries.concat(externalTaskPriority(element, bpmnFactory, { + getBusinessObject: function(element) { + if (!is(bo, 'bpmn:Participant')) { + return bo; + } + return bo.get('processRef'); + } + }, translate)); + } +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FieldInjectionProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FieldInjectionProps.js new file mode 100644 index 00000000..d5e88c2b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FieldInjectionProps.js @@ -0,0 +1,21 @@ +'use strict'; + +var ImplementationTypeHelper = require('../../../helper/ImplementationTypeHelper'); + +var fieldInjection = require('./implementation/FieldInjection'); + +module.exports = function(group, element, bpmnFactory, translate) { + + var bo = ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element); + + if (!bo) { + return; + } + + var fieldInjectionEntry = fieldInjection(element, bpmnFactory, translate, { businessObject: bo }); + + if (fieldInjectionEntry && fieldInjectionEntry.length > 0) { + group.entries = group.entries.concat(fieldInjectionEntry); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FormProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FormProps.js new file mode 100644 index 00000000..e3b39cbe --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/FormProps.js @@ -0,0 +1,476 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + getExtensionElements = require('../../../helper/ExtensionElementsHelper').getExtensionElements, + removeEntry = require('../../../helper/ExtensionElementsHelper').removeEntry, + extensionElements = require('./implementation/ExtensionElements'), + properties = require('./implementation/Properties'), + entryFactory = require('../../../factory/EntryFactory'), + elementHelper = require('../../../helper/ElementHelper'), + cmdHelper = require('../../../helper/CmdHelper'), + formHelper = require('../../../helper/FormHelper'), + utils = require('../../../Utils'), + is = require('bpmn-js/lib/util/ModelUtil').is, + find = require('lodash/find'), + each = require('lodash/forEach'); + +function generateValueId() { + return utils.nextId('Value_'); +} + +/** + * Generate a form field specific textField using entryFactory. + * + * @param {string} options.id + * @param {string} options.label + * @param {string} options.modelProperty + * @param {function} options.validate + * + * @return {Object} an entryFactory.textField object + */ +function formFieldTextField(options, getSelectedFormField) { + + var id = options.id, + label = options.label, + modelProperty = options.modelProperty, + validate = options.validate; + + return entryFactory.textField({ + id: id, + label: label, + modelProperty: modelProperty, + get: function(element, node) { + var selectedFormField = getSelectedFormField(element, node) || {}, + values = {}; + + values[modelProperty] = selectedFormField[modelProperty]; + + return values; + }, + + set: function(element, values, node) { + var commands = []; + + if (typeof options.set === 'function') { + var cmd = options.set(element, values, node); + + if (cmd) { + commands.push(cmd); + } + } + + var formField = getSelectedFormField(element, node), + properties = {}; + + properties[modelProperty] = values[modelProperty] || undefined; + + commands.push(cmdHelper.updateBusinessObject(element, formField, properties)); + + return commands; + }, + hidden: function(element, node) { + return !getSelectedFormField(element, node); + }, + validate: validate + }); +} + +function ensureFormKeyAndDataSupported(element) { + return ( + is(element, 'bpmn:StartEvent') && !is(element.parent, 'bpmn:SubProcess') + ) || is(element, 'bpmn:UserTask'); +} + +module.exports = function(group, element, bpmnFactory, translate) { + + if (!ensureFormKeyAndDataSupported(element)) { + return; + } + + + /** + * Return the currently selected form field querying the form field select box + * from the DOM. + * + * @param {djs.model.Base} element + * @param {DOMElement} node - DOM element of any form field text input + * + * @return {ModdleElement} the currently selected form field + */ + function getSelectedFormField(element, node) { + var selected = formFieldsEntry.getSelected(element, node.parentNode); + + if (selected.idx === -1) { + return; + } + + return formHelper.getFormField(element, selected.idx); + } + + // [FormKey] form key text input field + group.entries.push(entryFactory.textField({ + id : 'form-key', + label : translate('Form Key'), + modelProperty: 'formKey', + get: function(element, node) { + var bo = getBusinessObject(element); + + return { + formKey: bo.get('activiti:formKey') + }; + }, + set: function(element, values, node) { + var bo = getBusinessObject(element), + formKey = values.formKey || undefined; + + return cmdHelper.updateBusinessObject(element, bo, { 'activiti:formKey': formKey }); + } + })); + + // [FormData] form field select box + var formFieldsEntry = extensionElements(element, bpmnFactory, { + id: 'form-fields', + label: translate('Form Fields'), + modelProperty: 'id', + prefix: 'FormProperty', + createExtensionElement: function(element, extensionElements, value) { + var bo = getBusinessObject(element), commands = []; + + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory); + commands.push(cmdHelper.updateProperties(element, { extensionElements: extensionElements })); + } + /* var formData = formHelper.getFormData(element); + + if (!formData) { + formData = elementHelper.createElement('activiti:FormData', { fields: [] }, extensionElements, bpmnFactory); + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [formData], + [] + )); + }*/ + /**activiti 是向 extensionElements 下追加元素,而不是 formData 下,*/ + var field = elementHelper.createElement('activiti:FormProperty', { id: value }, extensionElements, bpmnFactory); + if (typeof extensionElements.values !== 'undefined') { + commands.push(cmdHelper.addElementsTolist(element, extensionElements, 'values', [ field ])); + } else { + commands.push(cmdHelper.updateBusinessObject(element, extensionElements, { + values: [ field ] + })); + } + return commands; + }, + removeExtensionElement: function(element, extensionElements, value, idx) { + var fields = formHelper.getFormFields(element); + var entry = fields[idx], + commands = []; + + if (fields.length < 2) { + commands.push(removeEntry(getBusinessObject(element), element, extensionElements)); + } else { + commands.push(cmdHelper.removeElementsFromList(element, extensionElements, 'values', null, [entry])); + /* if (entry.id === formData.get('businessKey')) { + commands.push(cmdHelper.updateBusinessObject(element, extensionElements, { 'businessKey': undefined })); + }*/ + } + + return commands; + }, + getExtensionElements: function(element) { + return formHelper.getFormFields(element); + }, + hideExtensionElements: function(element, node) { + return false; + } + }); + group.entries.push(formFieldsEntry); + + + // [FormData] Form Field label + group.entries.push(entryFactory.label({ + id: 'form-field-header', + labelText: translate('Form Field'), + showLabel: function(element, node) { + return !!getSelectedFormField(element, node); + } + })); + + // [FormData] form field id text input field + group.entries.push(entryFactory.validationAwareTextField({ + id: 'form-field-id', + label: translate('ID'), + modelProperty: 'id', + + getProperty: function(element, node) { + var selectedFormField = getSelectedFormField(element, node) || {}; + + return selectedFormField.id; + }, + + setProperty: function(element, properties, node) { + var formField = getSelectedFormField(element, node); + + return cmdHelper.updateBusinessObject(element, formField, properties); + }, + + hidden: function(element, node) { + return !getSelectedFormField(element, node); + }, + + validate: function(element, values, node) { + + var formField = getSelectedFormField(element, node); + + if (formField) { + + var idValue = values.id; + + if (!idValue || idValue.trim() === '') { + return { id: 'Form field id must not be empty' }; + } + + var formFields = formHelper.getFormFields(element); + + var existingFormField = find(formFields, function(f) { + return f !== formField && f.id === idValue; + }); + + if (existingFormField) { + return { id: 'Form field id already used in form data.' }; + } + } + } + })); + + // [FormData] form field type combo box + group.entries.push(entryFactory.comboBox({ + id: 'form-field-type', + label: translate('Type'), + selectOptions: [ + { name: 'string', value: 'string' }, + { name: 'long', value: 'long' }, + { name: 'boolean', value: 'boolean' }, + { name: 'date', value: 'date' }, + { name: 'enum', value: 'enum' } + ], + modelProperty: 'type', + emptyParameter: true, + + get: function(element, node) { + var selectedFormField = getSelectedFormField(element, node); + + if (selectedFormField) { + return { type: selectedFormField.type }; + } else { + return {}; + } + }, + set: function(element, values, node) { + var selectedFormField = getSelectedFormField(element, node), + commands = []; + + if (selectedFormField.type === 'enum' && values.type !== 'enum') { + // delete activiti:value objects from formField.values when switching from type enum + commands.push(cmdHelper.updateBusinessObject(element, selectedFormField, { values: undefined })); + } + commands.push(cmdHelper.updateBusinessObject(element, selectedFormField, values)); + + return commands; + }, + hidden: function(element, node) { + return !getSelectedFormField(element, node); + } + })); + + // [FormData] form field label text input field + group.entries.push(formFieldTextField({ + id: 'form-field-label', + label: translate('Label'), + modelProperty: 'label' + }, getSelectedFormField)); + + // [FormData] form field defaultValue text input field + group.entries.push(formFieldTextField({ + id: 'form-field-defaultValue', + label: translate('Default Value'), + modelProperty: 'defaultValue' + }, getSelectedFormField)); + + + // [FormData] form field enum values label + group.entries.push(entryFactory.label({ + id: 'form-field-enum-values-header', + labelText: translate('Values'), + divider: true, + showLabel: function(element, node) { + var selectedFormField = getSelectedFormField(element, node); + + return selectedFormField && selectedFormField.type === 'enum'; + } + })); + + // [FormData] form field enum values table + group.entries.push(entryFactory.table({ + id: 'form-field-enum-values', + labels: [ translate('Id'), translate('Name') ], + modelProperties: [ 'id', 'name' ], + addLabel:translate('Add Value'), + show: function(element, node) { + var selectedFormField = getSelectedFormField(element, node); + + return selectedFormField && selectedFormField.type === 'enum'; + }, + getElements: function(element, node) { + var selectedFormField = getSelectedFormField(element, node); + + return formHelper.getEnumValues(selectedFormField); + }, + addElement: function(element, node) { + var selectedFormField = getSelectedFormField(element, node), + id = generateValueId(); + + var enumValue = elementHelper.createElement( + 'activiti:Value', + { id: id, name: undefined }, + getBusinessObject(element), + bpmnFactory + ); + + return cmdHelper.addElementsTolist(element, selectedFormField, 'values', [enumValue]); + }, + removeElement: function(element, node, idx) { + var selectedFormField = getSelectedFormField(element, node), + enumValue = selectedFormField.values[idx]; + + return cmdHelper.removeElementsFromList(element, selectedFormField, 'values', null, [enumValue]); + }, + updateElement: function(element, value, node, idx) { + var selectedFormField = getSelectedFormField(element, node), + enumValue = selectedFormField.values[idx]; + + value.name = value.name || undefined; + return cmdHelper.updateBusinessObject(element, enumValue, value); + }, + validate: function(element, value, node, idx) { + + var selectedFormField = getSelectedFormField(element, node), + enumValue = selectedFormField.values[idx]; + + if (enumValue) { + // check if id is valid + var validationError = utils.isIdValid(enumValue, value.id, translate); + + if (validationError) { + return { id: validationError }; + } + } + } + })); + + // [FormData] Validation label + group.entries.push(entryFactory.label({ + id: 'form-field-validation-header', + labelText: translate('Validation'), + divider: true, + showLabel: function(element, node) { + return !!getSelectedFormField(element, node); + } + })); + + // [FormData] form field constraints table + group.entries.push(entryFactory.table({ + id: 'constraints-list', + modelProperties: [ 'name', 'config' ], + labels: [ translate('Name'), translate('Config') ], + addLabel: translate('Add Constraint'), + getElements: function(element, node) { + var formField = getSelectedFormField(element, node); + + return formHelper.getConstraints(formField); + }, + addElement: function(element, node) { + + var commands = [], + formField = getSelectedFormField(element, node), + validation = formField.validation; + + if (!validation) { + // create validation business object and add it to form data, if it doesn't exist + validation = elementHelper.createElement('activiti:Validation', {}, getBusinessObject(element), bpmnFactory); + + commands.push(cmdHelper.updateBusinessObject(element, formField, { 'validation': validation })); + } + + var newConstraint = elementHelper.createElement( + 'activiti:Constraint', + { name: undefined, config: undefined }, + validation, + bpmnFactory + ); + + commands.push(cmdHelper.addElementsTolist(element, validation, 'constraints', [ newConstraint ])); + + return commands; + }, + updateElement: function(element, value, node, idx) { + var formField = getSelectedFormField(element, node), + constraint = formHelper.getConstraints(formField)[idx]; + + value.name = value.name || undefined; + value.config = value.config || undefined; + + return cmdHelper.updateBusinessObject(element, constraint, value); + }, + removeElement: function(element, node, idx) { + var commands = [], + formField = getSelectedFormField(element, node), + constraints = formHelper.getConstraints(formField), + currentConstraint = constraints[idx]; + + commands.push(cmdHelper.removeElementsFromList( + element, + formField.validation, + 'constraints', + null, + [ currentConstraint ] + )); + + if (constraints.length === 1) { + // remove activiti:validation if the last existing constraint has been removed + commands.push(cmdHelper.updateBusinessObject(element, formField, { validation: undefined })); + } + + return commands; + }, + show: function(element, node) { + return !!getSelectedFormField(element, node); + } + })); + + // [FormData] Properties label + group.entries.push(entryFactory.label({ + id: 'form-field-properties-header', + labelText: translate('Properties'), + divider: true, + showLabel: function(element, node) { + return !!getSelectedFormField(element, node); + } + })); + + // [FormData] activiti:properties table + group.entries.push(properties(element, bpmnFactory, { + id: 'form-field-properties', + modelProperties: [ 'id', 'value' ], + labels: [ translate('Id'), translate('Value') ], + getParent: function(element, node) { + return getSelectedFormField(element, node); + }, + show: function(element, node) { + return !!getSelectedFormField(element, node); + } + }, translate)); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/HistoryTimeToLiveProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/HistoryTimeToLiveProps.js new file mode 100644 index 00000000..09d3d201 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/HistoryTimeToLiveProps.js @@ -0,0 +1,27 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var historyTimeToLive = require('./implementation/HistoryTimeToLive'); + +module.exports = function(group, element, bpmnFactory, translate) { + var businessObject = getBusinessObject(element); + + if (is(element, 'activiti:Process') || + is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + + group.entries = group.entries.concat(historyTimeToLive(element, bpmnFactory, { + getBusinessObject: function(element) { + var bo = getBusinessObject(element); + + if (!is(bo, 'bpmn:Participant')) { + return bo; + } + + return bo.get('processRef'); + } + }, translate)); + + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputParameterProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputParameterProps.js new file mode 100644 index 00000000..57c531c3 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputParameterProps.js @@ -0,0 +1,11 @@ +'use strict'; + +var inputOutputParameter = require('./implementation/InputOutputParameter'); + +var assign = require('lodash/assign'); + +module.exports = function(group, element, bpmnFactory, options, translate) { + + group.entries = group.entries.concat(inputOutputParameter(element, bpmnFactory, assign({}, options), translate)); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputProps.js new file mode 100644 index 00000000..f7f41037 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/InputOutputProps.js @@ -0,0 +1,15 @@ +'use strict'; + +var inputOutput = require('./implementation/InputOutput'); + +module.exports = function(group, element, bpmnFactory, translate) { + + var inputOutputEntry = inputOutput(element, bpmnFactory, {}, translate); + + group.entries = group.entries.concat(inputOutputEntry.entries); + + return { + getSelectedParameter: inputOutputEntry.getSelectedParameter + }; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/JobConfigurationProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/JobConfigurationProps.js new file mode 100644 index 00000000..46b83e0d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/JobConfigurationProps.js @@ -0,0 +1,34 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var jobPriority = require('./implementation/JobPriority'), + jobRetryTimeCycle = require('./implementation/JobRetryTimeCycle'); + +module.exports = function(group, element, bpmnFactory, translate) { + var businessObject = getBusinessObject(element); + + if (is(element, 'activiti:JobPriorized') || + is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + + group.entries = group.entries.concat(jobPriority(element, bpmnFactory, { + getBusinessObject: function(element) { + var bo = getBusinessObject(element); + + if (!is(bo, 'bpmn:Participant')) { + return bo; + } + + return bo.get('processRef'); + } + }, translate)); + } + + if (is(element, 'activiti:AsyncCapable')) { + group.entries = group.entries.concat(jobRetryTimeCycle(element, bpmnFactory, { + getBusinessObject: getBusinessObject + }, translate)); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerDetailProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerDetailProps.js new file mode 100644 index 00000000..ce34192b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerDetailProps.js @@ -0,0 +1,208 @@ +'use strict'; + +var entryFactory = require('../../../factory/EntryFactory'); + +var cmdHelper = require('../../../helper/CmdHelper'), + ImplementationTypeHelper = require('../../../helper/ImplementationTypeHelper'), + + scriptImplementation = require('./implementation/Script'); + + +module.exports = function(group, element, bpmnFactory, options, translate) { + + var LISTENER_TYPE_LABEL = { + class: translate('Java Class'), + expression: translate('Expression'), + delegateExpression: translate('Delegate Expression'), + script: translate('Script') + }; + + options = options || {}; + + var getSelectedListener = options.getSelectedListener; + + var classProp = 'class', + expressionProp = 'expression', + delegateExpressionProp = 'delegateExpression', + scriptProp = 'script'; + + var executionListenerEventTypeOptions = ImplementationTypeHelper.isSequenceFlow(element) ? [ + { name: translate('take'), value: 'take' } + ] : [ + { name: translate('start'), value: 'start' }, + { name: translate('end'), value: 'end' } + ]; + + var taskListenerEventTypeOptions = [ + { name: translate('create'), value: 'create' }, + { name: translate('assignment'), value: 'assignment' }, + { name: translate('complete'), value: 'complete' }, + { name: translate('delete'), value: 'delete' } + ]; + + var isSelected = function(element, node) { + return getSelectedListener(element, node); + }; + + group.entries.push(entryFactory.selectBox({ + id: 'listener-event-type', + label: translate('Event Type'), + modelProperty: 'eventType', + emptyParameter: false, + + get: function(element, node) { + + + var listener = getSelectedListener(element, node); + + var eventType = listener && listener.get('event'); + + return { + eventType: eventType + }; + }, + + set: function(element, values, node) { + var eventType = values.eventType; + + return cmdHelper.updateBusinessObject(element, getSelectedListener(element, node), { event: eventType }); + }, + + selectOptions: function(element, node) { + var eventTypeOptions; + + var selectedListener = getSelectedListener(element, node); + if (ImplementationTypeHelper.isTaskListener(selectedListener)) { + eventTypeOptions = taskListenerEventTypeOptions; + } else if (ImplementationTypeHelper.isExecutionListener(selectedListener)) { + eventTypeOptions = executionListenerEventTypeOptions; + } + + return eventTypeOptions; + + }, + + hidden: function(element, node) { + return !isSelected(element, node); + } + + })); + + + group.entries.push(entryFactory.selectBox({ + id: 'listener-type', + label: translate('Listener Type'), + selectOptions: [ + { value: classProp, name: translate('Java Class') }, + { value: expressionProp, name: translate('Expression') }, + { value: delegateExpressionProp, name: translate('Delegate Expression') }, + { value: scriptProp, name: translate('Script') } + ], + modelProperty: 'listenerType', + emptyParameter: false, + + get: function(element, node) { + var listener = getSelectedListener(element, node); + return { + listenerType: ImplementationTypeHelper.getImplementationType(listener) + }; + }, + + set: function(element, values, node) { + var listener = getSelectedListener(element, node), + listenerType = values.listenerType || undefined, + update = {}; + + update[classProp] = listenerType === classProp ? '' : undefined; + update[expressionProp] = listenerType === expressionProp ? '' : undefined; + update[delegateExpressionProp] = listenerType === delegateExpressionProp ? '' : undefined; + update[scriptProp] = listenerType === scriptProp ? bpmnFactory.create('activiti:Script') : undefined; + + return cmdHelper.updateBusinessObject(element, listener, update); + }, + + hidden: function(element, node) { + return !isSelected(element, node); + } + + })); + + + group.entries.push(entryFactory.textField({ + id: 'listener-value', + dataValueLabel: 'listenerValueLabel', + modelProperty: 'listenerValue', + + get: function(element, node) { + var value = {}, + listener = getSelectedListener(element, node), + listenerType = ImplementationTypeHelper.getImplementationType(listener); + + value.listenerValueLabel = LISTENER_TYPE_LABEL[listenerType] || ''; + value.listenerValue = (listener && listener.get(listenerType)) || undefined; + + return value; + }, + + set: function(element, values, node) { + var update = {}, + listener = getSelectedListener(element, node), + listenerType = ImplementationTypeHelper.getImplementationType(listener); + + update[listenerType] = values.listenerValue || ''; + + return cmdHelper.updateBusinessObject(element, listener, update); + }, + + hidden: function(element, node) { + var listener = getSelectedListener(element, node); + return !listener || listener.script; + }, + + validate: function(element, values) { + var value = values.listenerValue, + validate = {}; + + if (!value) { + validate.listenerValue = translate('Must provide a value'); + } + + return validate; + } + + })); + + var script = scriptImplementation('scriptFormat', 'value', true, translate); + + group.entries.push({ + id: 'listener-script-value', + html: '' + + script.template + + '', + + get: function(element, node) { + var listener = getSelectedListener(element, node); + return listener && listener.script ? script.get(element, listener.script) : {}; + }, + + set: function(element, values, node) { + var listener = getSelectedListener(element, node); + var update = script.set(element, values, listener); + return cmdHelper.updateBusinessObject(element, listener.script, update); + }, + + validate: function(element, values, node) { + var listener = getSelectedListener(element, node); + return listener && listener.script ? script.validate(element, values) : {}; + }, + + isScript: function(element, node) { + var listener = getSelectedListener(element, node); + return listener && listener.script; + }, + + script: script + + }); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerFieldInjectionProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerFieldInjectionProps.js new file mode 100644 index 00000000..06246dbd --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerFieldInjectionProps.js @@ -0,0 +1,20 @@ +'use strict'; + +var assign = require('lodash/assign'); + +var fieldInjection = require('./implementation/FieldInjection'); + +module.exports = function(group, element, bpmnFactory, options, translate) { + + options = assign({ + idPrefix: 'listener-', + insideListener: true + }, options); + + var fieldInjectionEntry = fieldInjection(element, bpmnFactory, translate, options); + + if (fieldInjectionEntry && fieldInjectionEntry.length > 0) { + group.entries = group.entries.concat(fieldInjectionEntry); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerProps.js new file mode 100644 index 00000000..93e14cb2 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ListenerProps.js @@ -0,0 +1,15 @@ +'use strict'; + +var listener = require('./implementation/Listener'); + +module.exports = function(group, element, bpmnFactory, translate) { + + var listenerEntry = listener(element, bpmnFactory, {}, translate); + + group.entries = group.entries.concat(listenerEntry.entries); + + return { + getSelectedListener: listenerEntry.getSelectedListener + }; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/MultiInstanceLoopProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/MultiInstanceLoopProps.js new file mode 100644 index 00000000..10c75631 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/MultiInstanceLoopProps.js @@ -0,0 +1,46 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is; + +var multiInstanceLoopCharacteristics = require('./implementation/MultiInstanceLoopCharacteristics'); + +var jobRetryTimeCycle = require('./implementation/JobRetryTimeCycle'), + asyncContinuation = require('./implementation/AsyncContinuation'); + + +function getLoopCharacteristics(element) { + var bo = getBusinessObject(element); + return bo.loopCharacteristics; +} + + +function ensureMultiInstanceSupported(element) { + var loopCharacteristics = getLoopCharacteristics(element); + return !!loopCharacteristics && is(loopCharacteristics, 'activiti:Collectable'); +} + +module.exports = function(group, element, bpmnFactory, translate) { + + if (!ensureMultiInstanceSupported(element)) { + return; + } + + // multi instance properties + group.entries = group.entries.concat(multiInstanceLoopCharacteristics(element, bpmnFactory, translate)); + + // async continuation /////////////////////////////////////////////////////// + group.entries = group.entries.concat(asyncContinuation(element, bpmnFactory, { + getBusinessObject: getLoopCharacteristics, + idPrefix: 'multiInstance-', + labelPrefix: translate('Multi Instance ') + }, translate)); + + + // retry time cycle ////////////////////////////////////////////////////////// + group.entries = group.entries.concat(jobRetryTimeCycle(element, bpmnFactory, { + getBusinessObject: getLoopCharacteristics, + idPrefix: 'multiInstance-', + labelPrefix: translate('Multi Instance ') + }, translate)); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/PropertiesProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/PropertiesProps.js new file mode 100644 index 00000000..9ff9ffc7 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/PropertiesProps.js @@ -0,0 +1,33 @@ +'use strict'; + +var properties = require('./implementation/Properties'), + elementHelper = require('../../../helper/ElementHelper'), + cmdHelper = require('../../../helper/CmdHelper'); + + +module.exports = function(group, element, bpmnFactory, translate) { + + var propertiesEntry = properties(element, bpmnFactory, { + id: 'properties', + modelProperties: [ 'name', 'value' ], + labels: [ translate('Name'), translate('Value') ], + + getParent: function(element, node, bo) { + return bo.extensionElements; + }, + + createParent: function(element, bo) { + var parent = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory); + var cmd = cmdHelper.updateBusinessObject(element, bo, { extensionElements: parent }); + return { + cmd: cmd, + parent: parent + }; + } + }, translate); + + if (propertiesEntry) { + group.entries.push(propertiesEntry); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ScriptTaskProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ScriptTaskProps.js new file mode 100644 index 00000000..f11680d7 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ScriptTaskProps.js @@ -0,0 +1,68 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is, + entryFactory = require('../../../factory/EntryFactory'), + cmdHelper = require('../../../helper/CmdHelper'), + scriptImplementation = require('./implementation/Script'); + + +module.exports = function(group, element, bpmnFactory, translate) { + var bo; + + if (is(element, 'bpmn:ScriptTask')) { + bo = getBusinessObject(element); + } + + if (!bo) { + return; + } + + var script = scriptImplementation('scriptFormat', 'script', false, translate); + group.entries.push({ + id: 'script-implementation', + label: translate('Script'), + html: script.template, + + get: function(element) { + return script.get(element, bo); + }, + + set: function(element, values, containerElement) { + var properties = script.set(element, values, containerElement); + + return cmdHelper.updateProperties(element, properties); + }, + + validate: function(element, values) { + return script.validate(element, values); + }, + + script : script, + + cssClasses: ['bpp-textfield'] + + }); + + group.entries.push(entryFactory.textField({ + id : 'scriptResultVariable', + label : translate('Result Variable'), + modelProperty : 'scriptResultVariable', + + get: function(element, propertyName) { + var boResultVariable = bo.get('activiti:resultVariable'); + + return { scriptResultVariable : boResultVariable }; + }, + + set: function(element, values, containerElement) { + return cmdHelper.updateProperties(element, { + 'activiti:resultVariable': values.scriptResultVariable.length + ? values.scriptResultVariable + : undefined + }); + } + + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ServiceTaskDelegateProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ServiceTaskDelegateProps.js new file mode 100644 index 00000000..d4a7cd93 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/ServiceTaskDelegateProps.js @@ -0,0 +1,151 @@ +'use strict'; + +var ImplementationTypeHelper = require('../../../helper/ImplementationTypeHelper'), + InputOutputHelper = require('../../../helper/InputOutputHelper'); + +var utils = require('../../../Utils'), + escapeHTML = utils.escapeHTML, + triggerClickEvent = utils.triggerClickEvent; + +var implementationType = require('./implementation/ImplementationType'), + delegate = require('./implementation/Delegate'), + external = require('./implementation/External'), + callable = require('./implementation/Callable'), + resultVariable = require('./implementation/ResultVariable'); + +var entryFactory = require('../../../factory/EntryFactory'); + +var domQuery = require('min-dom').query, + domClosest = require('min-dom').closest, + domClasses = require('min-dom').classes; + +function getImplementationType(element) { + return ImplementationTypeHelper.getImplementationType(element); +} + +function getBusinessObject(element) { + return ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element); +} + +function isDmnCapable(element) { + return ImplementationTypeHelper.isDmnCapable(element); +} + +function isExternalCapable(element) { + return ImplementationTypeHelper.isExternalCapable(element); +} + +function isServiceTaskLike(element) { + return ImplementationTypeHelper.isServiceTaskLike(element); +} + +module.exports = function(group, element, bpmnFactory, translate) { + + if (!isServiceTaskLike(getBusinessObject(element))) { + return; + } + + var hasDmnSupport = isDmnCapable(element); + var hasExternalSupport = isExternalCapable(getBusinessObject(element)); + + // implementation type //////////////////////////////////// + + group.entries = group.entries.concat(implementationType(element, bpmnFactory, { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType, + hasDmnSupport: hasDmnSupport, + hasExternalSupport: hasExternalSupport, + hasServiceTaskLikeSupport: true + }, translate)); + + + // delegate (class, expression, delegateExpression) ////////// + + group.entries = group.entries.concat(delegate(element, bpmnFactory, { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType + }, translate)); + + + // result variable ///////////////////////////////////////// + + group.entries = group.entries.concat(resultVariable(element, bpmnFactory, { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType, + hideResultVariable: function(element, node) { + return getImplementationType(element) !== 'expression'; + } + }, translate)); + + // external ////////////////////////////////////////////////// + + if (hasExternalSupport) { + group.entries = group.entries.concat(external(element, bpmnFactory, { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType + }, translate)); + } + + + // dmn //////////////////////////////////////////////////////// + + if (hasDmnSupport) { + group.entries = group.entries.concat(callable(element, bpmnFactory, { + getCallableType: getImplementationType + }, translate)); + } + + + // connector //////////////////////////////////////////////// + + var isConnector = function(element) { + return getImplementationType(element) === 'connector'; + }; + + group.entries.push(entryFactory.link({ + id: 'configureConnectorLink', + label: translate('Configure Connector'), + handleClick: function(element, node, event) { + + var connectorTabEl = getTabNode(node, 'connector'); + + if (connectorTabEl) { + triggerClickEvent(connectorTabEl); + } + + // suppress actual link click + return false; + }, + showLink: function(element, node) { + var link = domQuery('a', node); + link.textContent = ''; + + domClasses(link).remove('bpp-error-message'); + + if (isConnector(element)) { + var connectorId = InputOutputHelper.getConnector(element).get('connectorId'); + if (connectorId) { + link.textContent = translate('Configure Connector'); + } else { + link.innerHTML = ' ' + escapeHTML(translate('Must configure Connector')); + domClasses(link).add('bpp-error-message'); + } + + return true; + } + + return false; + } + })); + +}; + + + +// helpers /////////////////////////// + +function getTabNode(el, id) { + var containerEl = domClosest(el, '.bpp-properties-panel'); + + return domQuery('a[data-tab-target="' + id + '"]', containerEl); +} \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/StartEventInitiator.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/StartEventInitiator.js new file mode 100644 index 00000000..4412866c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/StartEventInitiator.js @@ -0,0 +1,23 @@ +'use strict'; + +var entryFactory = require('../../../factory/EntryFactory'), + is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + + +module.exports = function(group, element, translate) { + + var bo = getBusinessObject(element); + + if (!bo) { + return; + } + + if (is(element, 'activiti:Initiator') && !is(element.parent, 'bpmn:SubProcess')) { + group.entries.push(entryFactory.textField({ + id: 'initiator', + label: translate('Initiator'), + modelProperty: 'initiator' + })); + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/TasklistProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/TasklistProps.js new file mode 100644 index 00000000..94b8bcb8 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/TasklistProps.js @@ -0,0 +1,27 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var tasklist = require('./implementation/Tasklist'); + +module.exports = function(group, element, bpmnFactory, translate) { + var businessObject = getBusinessObject(element); + + if (is(element, 'activiti:Process') || + is(element, 'bpmn:Participant') && businessObject.get('processRef')) { + + group.entries = group.entries.concat(tasklist(element, bpmnFactory, { + getBusinessObject: function(element) { + var bo = getBusinessObject(element); + + if (!is(bo, 'bpmn:Participant')) { + return bo; + } + + return bo.get('processRef'); + } + }, translate)); + + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/UserTaskProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/UserTaskProps.js new file mode 100644 index 00000000..3f631d28 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/UserTaskProps.js @@ -0,0 +1,55 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + entryFactory = require('../../../factory/EntryFactory'); + + +module.exports = function(group, element, translate) { + if (is(element, 'activiti:Assignable')) { + + // Assignee + group.entries.push(entryFactory.textField({ + id : 'assignee', + label : translate('Assignee'), + modelProperty : 'assignee' + })); + + // Candidate Users + group.entries.push(entryFactory.textField({ + id : 'candidateUsers', + label : translate('Candidate Users'), + modelProperty : 'candidateUsers' + })); + + // Candidate Groups + group.entries.push(entryFactory.textField({ + id : 'candidateGroups', + label : translate('Candidate Groups'), + modelProperty : 'candidateGroups' + })); + + // Due Date + group.entries.push(entryFactory.textField({ + id : 'dueDate', + description : translate('The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)'), + label : translate('Due Date'), + modelProperty : 'dueDate' + })); + + // FollowUp Date + group.entries.push(entryFactory.textField({ + id : 'followUpDate', + description : translate('The follow up date as an EL expression (e.g. ${someDate} or an ' + + 'ISO date (e.g. 2015-06-26T09:54:00)'), + label : translate('Follow Up Date'), + modelProperty : 'followUpDate' + })); + + // priority + group.entries.push(entryFactory.textField({ + id : 'priority', + label : translate('Priority'), + modelProperty : 'priority' + })); + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VariableMappingProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VariableMappingProps.js new file mode 100644 index 00000000..0712bf1c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VariableMappingProps.js @@ -0,0 +1,397 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + isAny = require('bpmn-js/lib/features/modeling/util/ModelingUtil').isAny, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var filter = require('lodash/filter'); + +var extensionElementsHelper = require('../../../helper/ExtensionElementsHelper'), + cmdHelper = require('../../../helper/CmdHelper'), + elementHelper = require('../../../helper/ElementHelper'), + eventDefinitionHelper = require('../../../helper/EventDefinitionHelper'); + +var extensionElementsEntry = require('./implementation/ExtensionElements'); + +var entryFactory = require('../../../factory/EntryFactory'); + +/** + * return depend on parameter 'type' activiti:in or activiti:out extension elements + */ +function getActivitiInOutMappings(element, type) { + var bo = getBusinessObject(element); + + var signalEventDefinition = eventDefinitionHelper.getSignalEventDefinition(bo); + + return extensionElementsHelper.getExtensionElements(signalEventDefinition || bo, type) || []; +} + +/** + * return depend on parameter 'type' activiti:in or activiti:out extension elements + * with source or sourceExpression attribute + */ +function getVariableMappings(element, type) { + var activitiMappings = getActivitiInOutMappings(element, type); + + return filter(activitiMappings, function(mapping) { + return !mapping.businessKey; + }); +} + +function getInOutType(mapping) { + var inOutType = 'source'; + + if (mapping.variables === 'all') { + inOutType = 'variables'; + } + else if (typeof mapping.source !== 'undefined') { + inOutType = 'source'; + } + else if (typeof mapping.sourceExpression !== 'undefined') { + inOutType = 'sourceExpression'; + } + + return inOutType; +} + +var ACTIVITI_IN_EXTENSION_ELEMENT = 'activiti:In', + ACTIVITI_OUT_EXTENSION_ELEMENT = 'activiti:Out'; + +var WHITESPACE_REGEX = /\s/; + + +module.exports = function(group, element, bpmnFactory, translate) { + + var inOutTypeOptions = [ + { + name: translate('Source'), + value: 'source' + }, + { + name: translate('Source Expression'), + value: 'sourceExpression' + }, + { + name: translate('All'), + value: 'variables' + } + ]; + + var signalEventDefinition = eventDefinitionHelper.getSignalEventDefinition(element); + + if (!is(element, 'activiti:CallActivity') && !signalEventDefinition) { + return; + } + + if (signalEventDefinition && !(isAny(element, [ + 'bpmn:IntermediateThrowEvent', + 'bpmn:EndEvent' + ]))) { + return; + } + + var isSelected = function(element, node) { + return !!getSelected(element, node); + }; + + var getSelected = function(element, node) { + var parentNode = node.parentNode; + var selection = inEntry.getSelected(element, parentNode); + + var parameter = getVariableMappings(element, ACTIVITI_IN_EXTENSION_ELEMENT)[selection.idx]; + + if (!parameter && outEntry) { + selection = outEntry.getSelected(element, parentNode); + parameter = getVariableMappings(element, ACTIVITI_OUT_EXTENSION_ELEMENT)[selection.idx]; + } + + return parameter; + }; + + var setOptionLabelValue = function(type) { + return function(element, node, option, property, value, idx) { + var variableMappings = getVariableMappings(element, type); + var mappingValue = variableMappings[idx]; + var label = (mappingValue.target || '') + ' := '; + var mappingType = getInOutType(mappingValue); + + if (mappingType === 'variables') { + label = 'all'; + } + else if (mappingType === 'source') { + label = label + (mappingValue.source || ''); + } + else if (mappingType === 'sourceExpression') { + label = label + (mappingValue.sourceExpression || ''); + } else { + label = label + ''; + } + + option.text = label; + }; + }; + + var newElement = function(type) { + return function(element, extensionElements, value) { + var newElem = elementHelper.createElement(type, { source: '' }, extensionElements, bpmnFactory); + + return cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newElem ]); + }; + }; + + var removeElement = function(type) { + return function(element, extensionElements, value, idx) { + var variablesMappings= getVariableMappings(element, type); + var mapping = variablesMappings[idx]; + + if (mapping) { + return extensionElementsHelper + .removeEntry(signalEventDefinition || getBusinessObject(element), element, mapping); + } + }; + }; + + // in mapping for source and sourceExpression /////////////////////////////////////////////////////////////// + + var inEntry = extensionElementsEntry(element, bpmnFactory, { + id: 'variableMapping-in', + label: translate('In Mapping'), + modelProperty: 'source', + prefix: 'In', + idGeneration: false, + resizable: true, + businessObject: signalEventDefinition || getBusinessObject(element), + + createExtensionElement: newElement(ACTIVITI_IN_EXTENSION_ELEMENT), + removeExtensionElement: removeElement(ACTIVITI_IN_EXTENSION_ELEMENT), + + getExtensionElements: function(element) { + return getVariableMappings(element, ACTIVITI_IN_EXTENSION_ELEMENT); + }, + + onSelectionChange: function(element, node, event, scope) { + outEntry && outEntry.deselect(element, node.parentNode); + }, + + setOptionLabelValue: setOptionLabelValue(ACTIVITI_IN_EXTENSION_ELEMENT) + }); + group.entries.push(inEntry); + + // out mapping for source and sourceExpression /////////////////////////////////////////////////////// + + if (!signalEventDefinition) { + var outEntry = extensionElementsEntry(element, bpmnFactory, { + id: 'variableMapping-out', + label: translate('Out Mapping'), + modelProperty: 'source', + prefix: 'Out', + idGeneration: false, + resizable: true, + + createExtensionElement: newElement(ACTIVITI_OUT_EXTENSION_ELEMENT), + removeExtensionElement: removeElement(ACTIVITI_OUT_EXTENSION_ELEMENT), + + getExtensionElements: function(element) { + return getVariableMappings(element, ACTIVITI_OUT_EXTENSION_ELEMENT); + }, + + onSelectionChange: function(element, node, event, scope) { + inEntry.deselect(element, node.parentNode); + }, + + setOptionLabelValue: setOptionLabelValue(ACTIVITI_OUT_EXTENSION_ELEMENT) + }); + group.entries.push(outEntry); + } + + // label for selected mapping /////////////////////////////////////////////////////// + + group.entries.push(entryFactory.label({ + id: 'variableMapping-typeLabel', + get: function(element, node) { + var mapping = getSelected(element, node); + + var value = ''; + if (is(mapping, ACTIVITI_IN_EXTENSION_ELEMENT)) { + value = translate('In Mapping'); + } + else if (is(mapping, ACTIVITI_OUT_EXTENSION_ELEMENT)) { + value = translate('Out Mapping'); + } + + return { + label: value + }; + }, + + showLabel: function(element, node) { + return isSelected(element, node); + } + })); + + + group.entries.push(entryFactory.selectBox({ + id: 'variableMapping-inOutType', + label: translate('Type'), + selectOptions: inOutTypeOptions, + modelProperty: 'inOutType', + get: function(element, node) { + var mapping = getSelected(element, node) || {}; + return { + inOutType: getInOutType(mapping) + }; + }, + set: function(element, values, node) { + var inOutType = values.inOutType; + + var props = { + 'source' : undefined, + 'sourceExpression' : undefined, + 'variables' : undefined + }; + + if (inOutType === 'source') { + props.source = ''; + } + else if (inOutType === 'sourceExpression') { + props.sourceExpression = ''; + } + else if (inOutType === 'variables') { + props.variables = 'all'; + props.target = undefined; + } + + var mapping = getSelected(element, node); + return cmdHelper.updateBusinessObject(element, mapping, props); + }, + hidden: function(element, node) { + return !isSelected(element, node); + } + + })); + + + group.entries.push(entryFactory.textField({ + id: 'variableMapping-source', + dataValueLabel: 'sourceLabel', + modelProperty: 'source', + get: function(element, node) { + var mapping = getSelected(element, node) || {}; + + var label = ''; + var inOutType = getInOutType(mapping); + if (inOutType === 'source') { + label = translate('Source'); + } + else if (inOutType === 'sourceExpression') { + label = translate('Source Expression'); + } + + return { + source: mapping[inOutType], + sourceLabel: label + }; + }, + set: function(element, values, node) { + values.source = values.source || undefined; + + var mapping = getSelected(element, node); + var inOutType = getInOutType(mapping); + + var props = {}; + props[inOutType] = values.source || ''; + + return cmdHelper.updateBusinessObject(element, mapping, props); + }, + // one of both (source or sourceExpression) must have a value to make + // the configuration easier and more understandable + // it is not engine conform + validate: function(element, values, node) { + var mapping = getSelected(element, node); + + var validation = {}; + if (mapping) { + if (!values.source) { + validation.source = + validation.source = values.sourceLabel ? + translate('Mapping must have a {value}', { value: values.sourceLabel.toLowerCase() }) : + translate('Mapping must have a value'); + } + + var inOutType = getInOutType(mapping); + + if (WHITESPACE_REGEX.test(values.source) && inOutType !== 'sourceExpression') { + validation.source = translate('{label} must not contain whitespace', { label: values.sourceLabel }); + } + } + + return validation; + }, + hidden: function(element, node) { + var selectedMapping = getSelected(element, node); + return !selectedMapping || (selectedMapping && selectedMapping.variables); + } + })); + + + group.entries.push(entryFactory.textField({ + id: 'variableMapping-target', + label: translate('Target'), + modelProperty: 'target', + get: function(element, node) { + return { + target: (getSelected(element, node) || {}).target + }; + }, + set: function(element, values, node) { + values.target = values.target || undefined; + var mapping = getSelected(element, node); + return cmdHelper.updateBusinessObject(element, mapping, values); + }, + validate: function(element, values, node) { + var mapping = getSelected(element, node); + + var validation = {}; + if (mapping) { + var mappingType = getInOutType(mapping); + + if (!values.target && mappingType !== 'variables') { + validation.target = translate('Mapping must have a target'); + } + + if (values.target + && WHITESPACE_REGEX.test(values.target) + && mappingType !== 'variables') { + validation.target = translate('Target must not contain whitespace'); + } + } + + return validation; + }, + hidden: function(element, node) { + var selectedMapping = getSelected(element, node); + return !selectedMapping || (selectedMapping && selectedMapping.variables); + } + })); + + + group.entries.push(entryFactory.checkbox({ + id: 'variableMapping-local', + label: translate('Local'), + modelProperty: 'local', + get: function(element, node) { + return { + local: (getSelected(element, node) || {}).local + }; + }, + set: function(element, values, node) { + values.local = values.local || false; + var mapping = getSelected(element, node); + return cmdHelper.updateBusinessObject(element, mapping, values); + }, + hidden: function(element, node) { + return !isSelected(element, node); + } + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VersionTagProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VersionTagProps.js new file mode 100644 index 00000000..b36244fe --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/VersionTagProps.js @@ -0,0 +1,45 @@ +'use strict'; + +var entryFactory = require('../../../factory/EntryFactory'), + cmdHelper = require('../../../helper/CmdHelper'), + is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +module.exports = function(group, element, translate) { + + var bo = getBusinessObject(element); + + if (!bo) { + return; + } + + if (is(element, 'bpmn:Process') || is(element, 'bpmn:Participant') && bo.get('processRef')) { + var versionTagEntry = entryFactory.textField({ + id: 'versionTag', + label: translate('Version Tag'), + modelProperty: 'versionTag' + }); + + // in participants we have to change the default behavior of set and get + if (is(element, 'bpmn:Participant')) { + versionTagEntry.get = function(element) { + var processBo = bo.get('processRef'); + + return { + versionTag: processBo.get('activiti:versionTag') + }; + }; + + versionTagEntry.set = function(element, values) { + var processBo = bo.get('processRef'); + + return cmdHelper.updateBusinessObject(element, processBo, { + 'activiti:versionTag': values.versionTag || undefined + }); + }; + } + + group.entries.push(versionTagEntry); + + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/AsyncContinuation.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/AsyncContinuation.js new file mode 100644 index 00000000..78b8a5a4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/AsyncContinuation.js @@ -0,0 +1,130 @@ +'use strict'; + +var assign = require('lodash/assign'); + +var entryFactory = require('../../../../factory/EntryFactory'); + +var asyncCapableHelper = require('../../../../helper/AsyncCapableHelper'), + eventDefinitionHelper = require('../../../../helper/EventDefinitionHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +function isAsyncBefore(bo) { + return asyncCapableHelper.isAsyncBefore(bo); +} + +function isAsyncAfter(bo) { + return asyncCapableHelper.isAsyncAfter(bo); +} + +function isExclusive(bo) { + return asyncCapableHelper.isExclusive(bo); +} + +function removeFailedJobRetryTimeCycle(bo, element) { + return asyncCapableHelper.removeFailedJobRetryTimeCycle(bo, element); +} + +function canRemoveFailedJobRetryTimeCycle(element) { + return !eventDefinitionHelper.getTimerEventDefinition(element); +} + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var idPrefix = options.idPrefix || '', + labelPrefix = options.labelPrefix || ''; + + + var asyncBeforeEntry = entryFactory.checkbox({ + id: idPrefix + 'asyncBefore', + label: labelPrefix + translate('Asynchronous Before'), + modelProperty: 'asyncBefore', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { + asyncBefore: isAsyncBefore(bo) + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + var asyncBefore = !!values.asyncBefore; + + var props = { + 'activiti:asyncBefore': asyncBefore, + 'activiti:async': false + }; + + var commands = []; + if (!isAsyncAfter(bo) && !asyncBefore) { + props = assign({ 'activiti:exclusive' : true }, props); + if (canRemoveFailedJobRetryTimeCycle(element)) { + commands.push(removeFailedJobRetryTimeCycle(bo, element)); + } + } + + commands.push(cmdHelper.updateBusinessObject(element, bo, props)); + return commands; + } + }); + + + var asyncAfterEntry = entryFactory.checkbox({ + id: idPrefix + 'asyncAfter', + label: labelPrefix + translate('Asynchronous After'), + modelProperty: 'asyncAfter', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { + asyncAfter: isAsyncAfter(bo) + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + var asyncAfter = !!values.asyncAfter; + + var props = { + 'activiti:asyncAfter': asyncAfter + }; + + var commands = []; + if (!isAsyncBefore(bo) && !asyncAfter) { + props = assign({ 'activiti:exclusive' : true }, props); + if (canRemoveFailedJobRetryTimeCycle(element)) { + commands.push(removeFailedJobRetryTimeCycle(bo, element)); + } + } + + commands.push(cmdHelper.updateBusinessObject(element, bo, props)); + return commands; + } + }); + + + var exclusiveEntry = entryFactory.checkbox({ + id: idPrefix + 'exclusive', + label: labelPrefix + translate('Exclusive'), + modelProperty: 'exclusive', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { exclusive: isExclusive(bo) }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { 'activiti:exclusive': !!values.exclusive }); + }, + + hidden: function(element) { + var bo = getBusinessObject(element); + return bo && !isAsyncAfter(bo) && !isAsyncBefore(bo); + } + }); + + return [ asyncBeforeEntry, asyncAfterEntry, exclusiveEntry ]; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Callable.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Callable.js new file mode 100644 index 00000000..a9c84c47 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Callable.js @@ -0,0 +1,625 @@ +'use strict'; + +var cmdHelper = require('../../../../helper/CmdHelper'), + entryFactory = require('../../../../factory/EntryFactory'), + elementHelper = require('../../../../helper/ElementHelper'), + extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'); + + +var resultVariable = require('./ResultVariable'); + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var forEach = require('lodash/forEach'); + +var attributeInfo = { + bpmn: { + element: 'calledElement', + binding: 'activiti:calledElementBinding', + version: 'activiti:calledElementVersion', + versionTag: 'activiti:calledElementVersionTag', + tenantId: 'activiti:calledElementTenantId' + }, + + cmmn: { + element: 'activiti:caseRef', + binding: 'activiti:caseBinding', + version: 'activiti:caseVersion', + tenantId: 'activiti:caseTenantId' + }, + + dmn: { + element: 'activiti:decisionRef', + binding: 'activiti:decisionRefBinding', + version: 'activiti:decisionRefVersion', + versionTag: 'activiti:decisionRefVersionTag', + tenantId: 'activiti:decisionRefTenantId' + } +}; + +var mapDecisionResultOptions = [ + { + name: 'singleEntry (TypedValue)', + value: 'singleEntry' + }, + { + name:'singleResult (Map)', + value:'singleResult' + }, + { + name:'collectEntries (List)', + value:'collectEntries' + }, + { + name:'resultList (List>)', + value:'resultList' + } +]; + +var delegateVariableMappingOptions = [ + { + name: 'variableMappingClass', + value: 'variableMappingClass' + }, + { + name: 'variableMappingDelegateExpression', + value: 'variableMappingDelegateExpression' + } +]; + +function getActivitiInWithBusinessKey(element) { + var activitiIn = [], + bo = getBusinessObject(element); + + var activitiInParams = extensionElementsHelper.getExtensionElements(bo, 'activiti:In'); + if (activitiInParams) { + forEach(activitiInParams, function(param) { + if (param.businessKey !== undefined) { + activitiIn.push(param); + } + }); + } + return activitiIn; +} + +function setBusinessKey(element, text, bpmnFactory) { + var commands = []; + + var activitiInWithBusinessKey = getActivitiInWithBusinessKey(element); + + if (activitiInWithBusinessKey.length) { + commands.push(cmdHelper.updateBusinessObject(element, activitiInWithBusinessKey[0], { + businessKey: text + })); + } else { + var bo = getBusinessObject(element), + extensionElements = bo.extensionElements; + + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory); + commands.push(cmdHelper.updateProperties(element, { extensionElements: extensionElements })); + } + + var activitiIn = elementHelper.createElement( + 'activiti:In', + { 'businessKey': text }, + extensionElements, + bpmnFactory + ); + + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [ activitiIn ],[] + )); + } + + return commands; +} + +function deleteBusinessKey(element) { + var activitiInExtensions = getActivitiInWithBusinessKey(element); + var commands = []; + forEach(activitiInExtensions, function(elem) { + commands.push(extensionElementsHelper.removeEntry(getBusinessObject(element), element, elem)); + }); + return commands; +} + +function isSupportedCallableType(type) { + return [ 'bpmn', 'cmmn', 'dmn' ].indexOf(type) !== -1; +} + +module.exports = function(element, bpmnFactory, options, translate) { + + var bindingOptions = [ + { + name: translate('latest'), + value: 'latest' + }, + { + name: translate('deployment'), + value: 'deployment' + }, + { + name: translate('version'), + value: 'version' + }, + { + name: translate('versionTag'), + value: 'versionTag' + } + ]; + + var getCallableType = options.getCallableType; + + var entries = []; + + function getAttribute(element, prop) { + var type = getCallableType(element); + return (attributeInfo[type] || {})[prop]; + } + + function getCallActivityBindingValue(element) { + var type = getCallableType(element); + var bo = getBusinessObject(element); + var attr = (attributeInfo[type] || {}).binding; + return bo.get(attr); + } + + function getDelegateVariableMappingType(element) { + var bo = getBusinessObject(element); + + var boVariableMappingClass = bo.get('activiti:variableMappingClass'), + boVariableMappingDelegateExpression = bo.get('activiti:variableMappingDelegateExpression'); + + var delegateVariableMappingType = ''; + if (typeof boVariableMappingClass !== 'undefined') { + delegateVariableMappingType = 'variableMappingClass'; + } else + + if (typeof boVariableMappingDelegateExpression !== 'undefined') { + delegateVariableMappingType = 'variableMappingDelegateExpression'; + } + + return delegateVariableMappingType; + } + + + entries.push(entryFactory.textField({ + id: 'callable-element-ref', + dataValueLabel: 'callableElementLabel', + modelProperty: 'callableElementRef', + + get: function(element, node) { + var callableElementRef; + + var attr = getAttribute(element, 'element'); + if (attr) { + var bo = getBusinessObject(element); + callableElementRef = bo.get(attr); + } + + var label = ''; + var type = getCallableType(element); + if (type === 'bpmn') { + label = translate('Called Element'); + } + else if (type === 'cmmn') { + label = translate('Case Ref'); + } + else if (type === 'dmn') { + label = translate('Decision Ref'); + } + + return { + callableElementRef: callableElementRef, + callableElementLabel: label + }; + }, + + set: function(element, values, node) { + var newCallableElementRef = values.callableElementRef; + var attr = getAttribute(element, 'element'); + + var props = {}; + props[attr] = newCallableElementRef || ''; + + return cmdHelper.updateProperties(element, props); + }, + + validate: function(element, values, node) { + var elementRef = values.callableElementRef; + var type = getCallableType(element); + return isSupportedCallableType(type) && !elementRef ? { callableElementRef: translate('Must provide a value') } : {}; + }, + + hidden: function(element, node) { + return !isSupportedCallableType(getCallableType(element)); + } + + })); + + entries.push(entryFactory.selectBox({ + id: 'callable-binding', + label: translate('Binding'), + selectOptions: function(element) { + var type = getCallableType(element); + var options; + + if (type === 'cmmn') { + options = bindingOptions.filter(function(bindingOption) { + return bindingOption.value !== 'versionTag'; + }); + } else { + options = bindingOptions; + } + return options; + }, + modelProperty: 'callableBinding', + + get: function(element, node) { + var callableBinding; + + var attr = getAttribute(element, 'binding'); + if (attr) { + var bo = getBusinessObject(element); + callableBinding = bo.get(attr) || 'latest'; + } + + return { + callableBinding: callableBinding + }; + }, + + set: function(element, values, node) { + var binding = values.callableBinding; + var attr = getAttribute(element, 'binding'), + attrVer = getAttribute(element, 'version'), + attrVerTag = getAttribute(element, 'versionTag'); + + var props = {}; + props[attr] = binding; + + // set version and versionTag values always to undefined to delete the existing value + props[attrVer] = undefined; + props[attrVerTag] = undefined; + + return cmdHelper.updateProperties(element, props); + }, + + hidden: function(element, node) { + return !isSupportedCallableType(getCallableType(element)); + } + + })); + + entries.push(entryFactory.textField({ + id: 'callable-version', + label: translate('Version'), + modelProperty: 'callableVersion', + + get: function(element, node) { + var callableVersion; + + var attr = getAttribute(element, 'version'); + if (attr) { + var bo = getBusinessObject(element); + callableVersion = bo.get(attr); + } + + return { + callableVersion: callableVersion + }; + }, + + set: function(element, values, node) { + var version = values.callableVersion; + var attr = getAttribute(element, 'version'); + + var props = {}; + props[attr] = version || undefined; + + return cmdHelper.updateProperties(element, props); + }, + + validate: function(element, values, node) { + var version = values.callableVersion; + + var type = getCallableType(element); + return ( + isSupportedCallableType(type) && + getCallActivityBindingValue(element) === 'version' && ( + !version ? { callableVersion: translate('Must provide a value') } : {} + ) + ); + }, + + hidden: function(element, node) { + var type = getCallableType(element); + return !isSupportedCallableType(type) || getCallActivityBindingValue(element) !== 'version'; + } + + })); + + entries.push(entryFactory.textField({ + id: 'callable-version-tag', + label: translate('Version Tag'), + modelProperty: 'versionTag', + + get: function(element, node) { + var versionTag; + + var attr = getAttribute(element, 'versionTag'); + + if (attr) { + var bo = getBusinessObject(element); + + versionTag = bo.get(attr); + } + + return { + versionTag: versionTag + }; + }, + + set: function(element, values, node) { + var versionTag = values.versionTag; + + var attr = getAttribute(element, 'versionTag'); + + var props = {}; + + props[attr] = versionTag || undefined; + + return cmdHelper.updateProperties(element, props); + }, + + validate: function(element, values, node) { + var versionTag = values.versionTag; + + var type = getCallableType(element); + + return ( + isSupportedCallableType(type) && + getCallActivityBindingValue(element) === 'versionTag' && ( + !versionTag ? { versionTag: translate('Must provide a value') } : {} + ) + ); + }, + + hidden: function(element, node) { + var type = getCallableType(element); + + return !isSupportedCallableType(type) || getCallActivityBindingValue(element) !== 'versionTag'; + } + + })); + + entries.push(entryFactory.textField({ + id: 'tenant-id', + label: translate('Tenant Id'), + modelProperty: 'tenantId', + + get: function(element, node) { + var tenantId; + + var attr = getAttribute(element, 'tenantId'); + if (attr) { + var bo = getBusinessObject(element); + tenantId = bo.get(attr); + } + + return { + tenantId: tenantId + }; + }, + + set: function(element, values, node) { + var tenantId = values.tenantId; + var attr = getAttribute(element, 'tenantId'); + + var props = {}; + props[attr] = tenantId || undefined; + + return cmdHelper.updateProperties(element, props); + }, + + hidden: function(element, node) { + var type = getCallableType(element); + return !isSupportedCallableType(type); + } + + })); + + if (is(getBusinessObject(element), 'bpmn:CallActivity')) { + entries.push(entryFactory.checkbox({ + id: 'callable-business-key', + label: translate('Business Key'), + modelProperty: 'callableBusinessKey', + + get: function(element, node) { + var activitiIn = getActivitiInWithBusinessKey(element); + + return { + callableBusinessKey: !!(activitiIn && activitiIn.length > 0) + }; + }, + + set: function(element, values, node) { + if (values.callableBusinessKey) { + return setBusinessKey(element, '#{execution.processBusinessKey}', bpmnFactory); + } else { + return deleteBusinessKey(element); + } + } + })); + } + + entries.push(entryFactory.textField({ + id: 'business-key-expression', + label: translate('Business Key Expression'), + modelProperty: 'businessKey', + + get: function(element, node) { + var activitiInWithBusinessKey = getActivitiInWithBusinessKey(element); + + return { + businessKey: ( + activitiInWithBusinessKey.length ? + activitiInWithBusinessKey[0].get('activiti:businessKey') : + undefined + ) + }; + }, + + set: function(element, values, node) { + var businessKey = values.businessKey; + + return setBusinessKey(element, businessKey, bpmnFactory); + }, + + validate: function(element, values, node) { + var businessKey = values.businessKey; + + return businessKey === '' ? { businessKey: translate('Must provide a value') } : {}; + }, + + hidden: function(element, node) { + return !getActivitiInWithBusinessKey(element).length; + } + + })); + + entries = entries.concat(resultVariable(element, bpmnFactory, { + id: 'dmn-resultVariable', + getBusinessObject: getBusinessObject, + getImplementationType: getCallableType, + hideResultVariable: function(element, node) { + return getCallableType(element) !== 'dmn'; + } + }, translate)); + + entries.push(entryFactory.selectBox({ + id: 'dmn-map-decision-result', + label: translate('Map Decision Result'), + selectOptions: mapDecisionResultOptions, + modelProperty: 'mapDecisionResult', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { + mapDecisionResult: bo.get('activiti:mapDecisionResult') || 'resultList' + }; + }, + + set: function(element, values, node) { + return cmdHelper.updateProperties(element, { + 'activiti:mapDecisionResult': values.mapDecisionResult || 'resultList' + }); + }, + + hidden: function(element, node) { + var bo = getBusinessObject(element); + var resultVariable = bo.get('activiti:resultVariable'); + return !(getCallableType(element) === 'dmn' && typeof resultVariable !== 'undefined'); + } + + })); + + + entries.push(entryFactory.selectBox({ + id: 'delegateVariableMappingType', + label: translate('Delegate Variable Mapping'), + selectOptions: delegateVariableMappingOptions, + emptyParameter: true, + modelProperty: 'delegateVariableMappingType', + + get: function(element, node) { + return { + delegateVariableMappingType : getDelegateVariableMappingType(element) + }; + }, + + set: function(element, values, node) { + var delegateVariableMappingType = values.delegateVariableMappingType; + + var props = { + 'activiti:variableMappingClass' : undefined, + 'activiti:variableMappingDelegateExpression' : undefined + }; + + if (delegateVariableMappingType === 'variableMappingClass') { + props['activiti:variableMappingClass'] = ''; + } + else if (delegateVariableMappingType === 'variableMappingDelegateExpression') { + props['activiti:variableMappingDelegateExpression'] = ''; + } + + return cmdHelper.updateProperties(element, props); + }, + + hidden: function(element, node) { + return (getCallableType(element) !== 'bpmn'); + } + + })); + + entries.push(entryFactory.textField({ + id: 'delegateVariableMapping', + dataValueLabel: 'delegateVariableMappingLabel', + modelProperty: 'delegateVariableMapping', + + get: function(element, node) { + var bo = getBusinessObject(element); + + var label = ''; + var delegateVariableMapping = undefined; + var type = getDelegateVariableMappingType(element); + + if (type === 'variableMappingClass') { + label = translate('Class'); + delegateVariableMapping = bo.get('activiti:variableMappingClass'); + } + else if (type === 'variableMappingDelegateExpression') { + label = translate('Delegate Expression'); + delegateVariableMapping = bo.get('activiti:variableMappingDelegateExpression'); + } + + return { + delegateVariableMapping: delegateVariableMapping, + delegateVariableMappingLabel: label + }; + }, + + set: function(element, values, node) { + var delegateVariableMapping = values.delegateVariableMapping; + + var attr = 'activiti:' + getDelegateVariableMappingType(element); + + var props = {}; + props[attr] = delegateVariableMapping || undefined; + + return cmdHelper.updateProperties(element, props); + }, + + validate: function(element, values, node) { + var delegateVariableMapping = values.delegateVariableMapping; + return ( + getCallableType(element) === 'bpmn' && ( + !delegateVariableMapping ? { delegateVariableMapping: translate('Must provide a value') } : {} + ) + ); + }, + + hidden: function(element, node) { + return !(getCallableType(element) === 'bpmn' && getDelegateVariableMappingType(element) !== ''); + } + + })); + + return entries; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/CandidateStarter.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/CandidateStarter.js new file mode 100644 index 00000000..e3b7b8ca --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/CandidateStarter.js @@ -0,0 +1,63 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var candidateStarterGroupsEntry = entryFactory.textField({ + id: 'candidateStarterGroups', + label: translate('Candidate Starter Groups'), + modelProperty: 'candidateStarterGroups', + description: translate('Specify more than one group as a comma separated list.'), + + get: function(element, node) { + var bo = getBusinessObject(element); + var candidateStarterGroups = bo.get('activiti:candidateStarterGroups'); + + return { + candidateStarterGroups: candidateStarterGroups ? candidateStarterGroups : '' + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:candidateStarterGroups': values.candidateStarterGroups || undefined + }); + } + + }); + + var candidateStarterUsersEntry = entryFactory.textField({ + id: 'candidateStarterUsers', + label: translate('Candidate Starter Users'), + modelProperty: 'candidateStarterUsers', + description: translate('Specify more than one user as a comma separated list.'), + + get: function(element, node) { + var bo = getBusinessObject(element); + var candidateStarterUsers = bo.get('activiti:candidateStarterUsers'); + + return { + candidateStarterUsers: candidateStarterUsers ? candidateStarterUsers : '' + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:candidateStarterUsers': values.candidateStarterUsers || undefined + }); + } + + }); + + return [ + candidateStarterGroupsEntry, + candidateStarterUsersEntry + ]; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Delegate.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Delegate.js new file mode 100644 index 00000000..51cf12b3 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Delegate.js @@ -0,0 +1,83 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var DELEGATE_TYPES = [ + 'class', + 'expression', + 'delegateExpression' +]; + +var PROPERTIES = { + class: 'activiti:class', + expression: 'activiti:expression', + delegateExpression: 'activiti:delegateExpression' +}; + +function isDelegate(type) { + return DELEGATE_TYPES.indexOf(type) !== -1; +} + +function getAttribute(type) { + return PROPERTIES[type]; +} + + +module.exports = function(element, bpmnFactory, options, translate) { + + var getImplementationType = options.getImplementationType, + getBusinessObject = options.getBusinessObject; + + function getDelegationLabel(type) { + switch (type) { + case 'class': + return translate('Java Class'); + case 'expression': + return translate('Expression'); + case 'delegateExpression': + return translate('Delegate Expression'); + default: + return ''; + } + } + + var delegateEntry = entryFactory.textField({ + id: 'delegate', + label: translate('Value'), + dataValueLabel: 'delegationLabel', + modelProperty: 'delegate', + + get: function(element, node) { + var bo = getBusinessObject(element); + var type = getImplementationType(element); + var attr = getAttribute(type); + var label = getDelegationLabel(type); + return { + delegate: bo.get(attr), + delegationLabel: label + }; + }, + + set: function(element, values, node) { + var bo = getBusinessObject(element); + var type = getImplementationType(element); + var attr = getAttribute(type); + var prop = {}; + prop[attr] = values.delegate || ''; + return cmdHelper.updateBusinessObject(element, bo, prop); + }, + + validate: function(element, values, node) { + return isDelegate(getImplementationType(element)) && !values.delegate ? { delegate: translate('Must provide a value') } : {}; + }, + + hidden: function(element, node) { + return !isDelegate(getImplementationType(element)); + } + + }); + + return [ delegateEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ErrorEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ErrorEventDefinition.js new file mode 100644 index 00000000..bf29bb7b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ErrorEventDefinition.js @@ -0,0 +1,65 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'), + elementReferenceProperty = require('../../../../provider/bpmn/parts/implementation/ElementReferenceProperty'); + +module.exports = function( + group, element, bpmnFactory, errorEventDefinition, + showErrorCodeVariable, showErrorMessageVariable, translate +) { + + + var getValue = function(modelProperty) { + return function(element) { + var modelPropertyValue = errorEventDefinition.get('activiti:' + modelProperty); + var value = {}; + + value[modelProperty] = modelPropertyValue; + return value; + }; + }; + + var setValue = function(modelProperty) { + return function(element, values) { + var props = {}; + + props['activiti:' + modelProperty] = values[modelProperty] || undefined; + + return cmdHelper.updateBusinessObject(element, errorEventDefinition, props); + }; + }; + + + group.entries = group.entries.concat( + elementReferenceProperty(element, errorEventDefinition, bpmnFactory, { + id: 'error-element-message', + label: translate('Error Message'), + referenceProperty: 'errorRef', + modelProperty: 'errorMessage' + }) + ); + + if (showErrorCodeVariable) { + group.entries.push(entryFactory.textField({ + id: 'errorCodeVariable', + label: translate('Error Code Variable'), + modelProperty : 'errorCodeVariable', + + get: getValue('errorCodeVariable'), + set: setValue('errorCodeVariable') + })); + } + + if (showErrorMessageVariable) { + group.entries.push(entryFactory.textField({ + id: 'errorMessageVariable', + label: translate('Error Message Variable'), + modelProperty: 'errorMessageVariable', + + get: getValue('errorMessageVariable'), + set: setValue('errorMessageVariable') + })); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExtensionElements.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExtensionElements.js new file mode 100644 index 00000000..51fad775 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExtensionElements.js @@ -0,0 +1,235 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var domQuery = require('min-dom').query, + domClosest = require('min-dom').closest, + domify = require('min-dom').domify, + forEach = require('lodash/forEach'); + +var elementHelper = require('../../../../helper/ElementHelper'), + cmdHelper = require('../../../../helper/CmdHelper'), + utils = require('../../../../Utils'), + escapeHTML = utils.escapeHTML; + +function getSelectBox(node, id) { + var currentTab = domClosest(node, 'div.bpp-properties-tab'); + var query = 'select[name=selectedExtensionElement]' + (id ? '[id=cam-extensionElements-' + id + ']' : ''); + return domQuery(query, currentTab); +} + +function getSelected(node, id) { + var selectBox = getSelectBox(node, id); + return { + value: (selectBox || {}).value, + idx: (selectBox || {}).selectedIndex + }; +} + +function generateElementId(prefix) { + prefix = prefix + '_'; + return utils.nextId(prefix); +} + +var CREATE_EXTENSION_ELEMENT_ACTION = 'create-extension-element', + REMOVE_EXTENSION_ELEMENT_ACTION = 'remove-extension-element'; + +module.exports = function(element, bpmnFactory, options, translate) { + + var id = options.id, + prefix = options.prefix || 'elem', + label = options.label || id, + idGeneration = (options.idGeneration === false) ? options.idGeneration : true, + businessObject = options.businessObject || getBusinessObject(element); + + var modelProperty = options.modelProperty || 'id'; + + var getElements = options.getExtensionElements; + + var createElement = options.createExtensionElement, + canCreate = typeof createElement === 'function'; + + var removeElement = options.removeExtensionElement, + canRemove = typeof removeElement === 'function'; + + var onSelectionChange = options.onSelectionChange; + + var hideElements = options.hideExtensionElements, + canBeHidden = typeof hideElements === 'function'; + + var setOptionLabelValue = options.setOptionLabelValue; + + var defaultSize = options.size || 5, + resizable = options.resizable; + + var reference = options.reference || undefined; + + var selectionChanged = function(element, node, event, scope) { + if (typeof onSelectionChange === 'function') { + return onSelectionChange(element, node, event, scope); + } + }; + + var createOption = function(value) { + return '' + escapeHTML(value) + ''; + }; + + var initSelectionSize = function(selectBox, optionsLength) { + if (resizable) { + selectBox.size = optionsLength > defaultSize ? optionsLength : defaultSize; + } + }; + + return { + id: id, + html: '' + + '' + escapeHTML(label) + '' + + '' + + '' + + '' + + (canCreate ? '' + + '+' + + '' : '') + + (canRemove ? '' + + '-' + + '' : '') + + '' + + '', + + get: function(element, node) { + var elements = getElements(element, node); + + var result = []; + forEach(elements, function(elem) { + result.push({ + extensionElementValue: elem.get(modelProperty) + }); + }); + + var selectBox = getSelectBox(node.parentNode, id); + initSelectionSize(selectBox, result.length); + + return result; + }, + + set: function(element, values, node) { + var action = this.__action; + delete this.__action; + + businessObject = businessObject || getBusinessObject(element); + + var bo = + (reference && businessObject.get(reference)) + ? businessObject.get(reference) + : businessObject; + + var extensionElements = bo.get('extensionElements'); + + if (action.id === CREATE_EXTENSION_ELEMENT_ACTION) { + var commands = []; + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory); + commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements })); + } + commands.push(createElement(element, extensionElements, action.value, node)); + return commands; + + } + else if (action.id === REMOVE_EXTENSION_ELEMENT_ACTION) { + return removeElement(element, extensionElements, action.value, action.idx, node); + } + + }, + + createListEntryTemplate: function(value, index, selectBox) { + initSelectionSize(selectBox, selectBox.options.length + 1); + return createOption(value.extensionElementValue); + }, + + deselect: function(element, node) { + var selectBox = getSelectBox(node, id); + selectBox.selectedIndex = -1; + }, + + getSelected: function(element, node) { + return getSelected(node, id); + }, + + setControlValue: function(element, node, option, property, value, idx) { + node.value = value; + + if (!setOptionLabelValue) { + node.text = value; + } else { + setOptionLabelValue(element, node, option, property, value, idx); + } + }, + + createElement: function(element, node) { + // create option template + var generatedId; + if (idGeneration) { + generatedId = generateElementId(prefix); + } + + var selectBox = getSelectBox(node, id); + var template = domify(createOption(generatedId)); + + // add new empty option as last child element + selectBox.appendChild(template); + + // select last child element + selectBox.lastChild.selected = 'selected'; + selectionChanged(element, node); + + // update select box size + initSelectionSize(selectBox, selectBox.options.length); + + this.__action = { + id: CREATE_EXTENSION_ELEMENT_ACTION, + value: generatedId + }; + + return true; + }, + + removeElement: function(element, node) { + var selection = getSelected(node, id); + + var selectBox = getSelectBox(node, id); + selectBox.removeChild(selectBox.options[selection.idx]); + + // update select box size + initSelectionSize(selectBox, selectBox.options.length); + + this.__action = { + id: REMOVE_EXTENSION_ELEMENT_ACTION, + value: selection.value, + idx: selection.idx + }; + + return true; + }, + + hideElements: function(element, entryNode, node, scopeNode) { + return !hideElements(element, entryNode, node, scopeNode); + }, + + disableRemove: function(element, entryNode, node, scopeNode) { + return (getSelected(entryNode, id) || {}).idx < 0; + }, + + selectElement: selectionChanged + }; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/External.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/External.js new file mode 100644 index 00000000..6df66959 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/External.js @@ -0,0 +1,44 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getImplementationType = options.getImplementationType, + getBusinessObject = options.getBusinessObject; + + function isExternal(element) { + return getImplementationType(element) === 'external'; + } + + var topicEntry = entryFactory.textField({ + id: 'externalTopic', + label: translate('Topic'), + modelProperty: 'externalTopic', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { externalTopic: bo.get('activiti:topic') }; + }, + + set: function(element, values, node) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:topic': values.externalTopic + }); + }, + + validate: function(element, values, node) { + return isExternal(element) && !values.externalTopic ? { externalTopic: translate('Must provide a value') } : {}; + }, + + hidden: function(element, node) { + return !isExternal(element); + } + + }); + + return [ topicEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExternalTaskPriority.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExternalTaskPriority.js new file mode 100644 index 00000000..f41aec1e --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ExternalTaskPriority.js @@ -0,0 +1,34 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var externalTaskPriorityEntry = entryFactory.textField({ + id: 'externalTaskPriority', + label: translate('Task Priority'), + modelProperty: 'taskPriority', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { + taskPriority: bo.get('activiti:taskPriority') + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:taskPriority': values.taskPriority || undefined + }); + } + + }); + + return [ externalTaskPriorityEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/FieldInjection.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/FieldInjection.js new file mode 100644 index 00000000..24f2922c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/FieldInjection.js @@ -0,0 +1,310 @@ +'use strict'; + +var extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'), + elementHelper = require('../../../../helper/ElementHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var utils = require('../../../../Utils'); + +var entryFactory = require('../../../../factory/EntryFactory'); + +var extensionElementsEntry = require('./ExtensionElements'); + +var ModelUtil = require('bpmn-js/lib/util/ModelUtil'), + getBusinessObject = ModelUtil.getBusinessObject; + +var assign = require('lodash/assign'); + + +var DEFAULT_PROPS = { + 'stringValue': undefined, + 'string': undefined, + 'expression': undefined +}; + +var ACTIVITI_FIELD_EXTENSION_ELEMENT = 'activiti:Field'; + +module.exports = function(element, bpmnFactory, translate, options) { + + options = options || {}; + + var insideListener = !!options.insideListener, + idPrefix = options.idPrefix || '', + getSelectedListener = options.getSelectedListener, + businessObject = options.businessObject || getBusinessObject(element); + + var entries = []; + + var isSelected = function(element, node) { + return getSelectedField(element, node); + }; + + function getSelectedField(element, node) { + var selected = fieldEntry.getSelected(element, node.parentNode); + + if (selected.idx === -1) { + return; + } + + var fields = getActivitiFields(element, node); + + return fields[selected.idx]; + } + + function getActivitiFields(element, node) { + if (!insideListener) { + return ( + businessObject && + extensionElementsHelper.getExtensionElements(businessObject, ACTIVITI_FIELD_EXTENSION_ELEMENT) + ) || []; + } + return getActivitiListenerFields(element, node); + } + + function getActivitiListenerFields(element, node) { + var selectedListener = getSelectedListener(element, node); + return selectedListener && selectedListener.fields || []; + } + + function getFieldType(bo) { + var fieldType = 'string'; + + var expressionValue = bo && bo.expression; + var stringValue = bo && (bo.string || bo.stringValue); + + if (typeof stringValue !== 'undefined') { + fieldType = 'string'; + } else if (typeof expressionValue !== 'undefined') { + fieldType = 'expression'; + } + + return fieldType; + } + + var setOptionLabelValue = function() { + return function(element, node, option, property, value, idx) { + var activitiFields = getActivitiFields(element, node); + var field = activitiFields[idx]; + + value = (field.name) ? field.name : ''; + + var label = idx + ' : ' + value; + + option.text = label; + }; + }; + + var newElement = function() { + return function(element, extensionElements, value, node) { + + var props = { + name: '', + string: '' + }; + + var newFieldElem; + + if (!insideListener) { + + newFieldElem = elementHelper.createElement(ACTIVITI_FIELD_EXTENSION_ELEMENT, props, extensionElements, bpmnFactory); + return cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newFieldElem ]); + + } else { + + var selectedListener = getSelectedListener(element, node); + newFieldElem = elementHelper.createElement(ACTIVITI_FIELD_EXTENSION_ELEMENT, props, selectedListener, bpmnFactory); + return cmdHelper.addElementsTolist(element, selectedListener, 'fields', [ newFieldElem ]); + + } + + }; + }; + + var removeElement = function() { + return function(element, extensionElements, value, idx, node) { + var activitiFields= getActivitiFields(element, node); + var field = activitiFields[idx]; + if (field) { + if (!insideListener) { + return extensionElementsHelper.removeEntry(businessObject, element, field); + } + var selectedListener = getSelectedListener(element, node); + return cmdHelper.removeElementsFromList(element, selectedListener, 'fields', null, [ field ]); + } + }; + }; + + + var fieldEntry = extensionElementsEntry(element, bpmnFactory, { + id : idPrefix + 'fields', + label : translate('Fields'), + modelProperty: 'fieldName', + idGeneration: 'false', + + businessObject: businessObject, + + createExtensionElement: newElement(), + removeExtensionElement: removeElement(), + + getExtensionElements: function(element, node) { + return getActivitiFields(element, node); + }, + + setOptionLabelValue: setOptionLabelValue() + + }); + entries.push(fieldEntry); + + + entries.push(entryFactory.validationAwareTextField({ + id: idPrefix + 'field-name', + label: translate('Name'), + modelProperty: 'fieldName', + + getProperty: function(element, node) { + return (getSelectedField(element, node) || {}).name; + }, + + setProperty: function(element, values, node) { + var selectedField = getSelectedField(element, node); + return cmdHelper.updateBusinessObject(element, selectedField, { name : values.fieldName }); + }, + + validate: function(element, values, node) { + var bo = getSelectedField(element, node); + + var validation = {}; + if (bo) { + var nameValue = values.fieldName; + + if (nameValue) { + if (utils.containsSpace(nameValue)) { + validation.fieldName = translate('Name must not contain spaces'); + } + } else { + validation.fieldName = translate('Parameter must have a name'); + } + } + + return validation; + }, + + hidden: function(element, node) { + return !isSelected(element, node); + } + + })); + + var fieldTypeOptions = [ + { + name: translate('String'), + value: 'string' + }, + { + name: translate('Expression'), + value: 'expression' + } + ]; + + entries.push(entryFactory.selectBox({ + id: idPrefix + 'field-type', + label: translate('Type'), + selectOptions: fieldTypeOptions, + modelProperty: 'fieldType', + + get: function(element, node) { + var bo = getSelectedField(element, node); + + var fieldType = getFieldType(bo); + + return { + fieldType: fieldType + }; + }, + + set: function(element, values, node) { + var props = assign({}, DEFAULT_PROPS); + + var fieldType = values.fieldType; + + if (fieldType === 'string') { + props.string = ''; + } + else if (fieldType === 'expression') { + props.expression = ''; + } + + return cmdHelper.updateBusinessObject(element, getSelectedField(element, node), props); + }, + + hidden: function(element, node) { + return !isSelected(element, node); + } + + })); + + + entries.push(entryFactory.textBox({ + id: idPrefix + 'field-value', + label: translate('Value'), + modelProperty: 'fieldValue', + + get: function(element, node) { + var bo = getSelectedField(element, node); + var fieldType = getFieldType(bo); + + var fieldValue; + + if (fieldType === 'string') { + fieldValue = bo && (bo.string || bo.stringValue); + } + else if (fieldType === 'expression') { + fieldValue = bo && bo.expression; + } + + return { + fieldValue: fieldValue + }; + }, + + set: function(element, values, node) { + var bo = getSelectedField(element, node); + var fieldType = getFieldType(bo); + + var props = assign({}, DEFAULT_PROPS); + + var fieldValue = values.fieldValue || undefined; + + if (fieldType === 'string') { + props.string = fieldValue; + } + else if (fieldType === 'expression') { + props.expression = fieldValue; + } + + return cmdHelper.updateBusinessObject(element, bo, props); + + }, + + validate: function(element, values, node) { + var bo = getSelectedField(element, node); + + var validation = {}; + if (bo) { + if (!values.fieldValue) { + validation.fieldValue = translate('Must provide a value'); + } + } + + return validation; + }, + + show: function(element, node) { + return isSelected(element, node); + } + + })); + + return entries; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/HistoryTimeToLive.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/HistoryTimeToLive.js new file mode 100644 index 00000000..6411b778 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/HistoryTimeToLive.js @@ -0,0 +1,35 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var historyTimeToLiveEntry = entryFactory.textField({ + id: 'historyTimeToLive', + label: translate('History Time To Live'), + modelProperty: 'historyTimeToLive', + + get: function(element, node) { + var bo = getBusinessObject(element); + var historyTimeToLive = bo.get('activiti:historyTimeToLive'); + + return { + historyTimeToLive: historyTimeToLive ? historyTimeToLive : '' + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:historyTimeToLive': values.historyTimeToLive || undefined + }); + } + + }); + + return [ historyTimeToLiveEntry ]; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ImplementationType.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ImplementationType.js new file mode 100644 index 00000000..09802573 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ImplementationType.js @@ -0,0 +1,173 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'), + extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'), + elementHelper = require('../../../../helper/ElementHelper'); + +var assign = require('lodash/assign'); +var map = require('lodash/map'); + +var DEFAULT_DELEGATE_PROPS = [ 'class', 'expression', 'delegateExpression' ]; + +var DELEGATE_PROPS = { + 'activiti:class': undefined, + 'activiti:expression': undefined, + 'activiti:delegateExpression': undefined, + 'activiti:resultVariable': undefined +}; + +var DMN_CAPABLE_PROPS = { + 'activiti:decisionRef': undefined, + 'activiti:decisionRefBinding': 'latest', + 'activiti:decisionRefVersion': undefined, + 'activiti:mapDecisionResult': 'resultList', + 'activiti:decisionRefTenantId': undefined +}; + + +var EXTERNAL_CAPABLE_PROPS = { + 'activiti:type': undefined, + 'activiti:topic': undefined +}; + +module.exports = function(element, bpmnFactory, options, translate) { + + var DEFAULT_OPTIONS = [ + { value: 'class', name: translate('Java Class') }, + { value: 'expression', name: translate('Expression') }, + { value: 'delegateExpression', name: translate('Delegate Expression') } + ]; + + var DMN_OPTION = [ + { value: 'dmn', name: translate('DMN') } + ]; + + var EXTERNAL_OPTION = [ + { value: 'external', name: translate('External') } + ]; + + var CONNECTOR_OPTION = [ + { value: 'connector', name: translate('Connector') } + ]; + + var SCRIPT_OPTION = [ + { value: 'script', name: translate('Script') } + ]; + + var getType = options.getImplementationType, + getBusinessObject = options.getBusinessObject; + + var hasDmnSupport = options.hasDmnSupport, + hasExternalSupport = options.hasExternalSupport, + hasServiceTaskLikeSupport = options.hasServiceTaskLikeSupport, + hasScriptSupport = options.hasScriptSupport; + + var entries = []; + + var selectOptions = DEFAULT_OPTIONS.concat([]); + + if (hasDmnSupport) { + selectOptions = selectOptions.concat(DMN_OPTION); + } + + if (hasExternalSupport) { + selectOptions = selectOptions.concat(EXTERNAL_OPTION); + } + + if (hasServiceTaskLikeSupport) { + selectOptions = selectOptions.concat(CONNECTOR_OPTION); + } + + if (hasScriptSupport) { + selectOptions = selectOptions.concat(SCRIPT_OPTION); + } + + selectOptions.push({ value: '' }); + + entries.push(entryFactory.selectBox({ + id : 'implementation', + label: translate('Implementation'), + selectOptions: selectOptions, + modelProperty: 'implType', + + get: function(element, node) { + return { + implType: getType(element) || '' + }; + }, + + set: function(element, values, node) { + var bo = getBusinessObject(element); + var oldType = getType(element); + var newType = values.implType; + + var props = assign({}, DELEGATE_PROPS); + + if (DEFAULT_DELEGATE_PROPS.indexOf(newType) !== -1) { + + var newValue = ''; + if (DEFAULT_DELEGATE_PROPS.indexOf(oldType) !== -1) { + newValue = bo.get('activiti:' + oldType); + } + props['activiti:' + newType] = newValue; + } + + if (hasDmnSupport) { + props = assign(props, DMN_CAPABLE_PROPS); + if (newType === 'dmn') { + props['activiti:decisionRef'] = ''; + } + } + + if (hasExternalSupport) { + props = assign(props, EXTERNAL_CAPABLE_PROPS); + if (newType === 'external') { + props['activiti:type'] = 'external'; + props['activiti:topic'] = ''; + } + } + + if (hasScriptSupport) { + props['activiti:script'] = undefined; + + if (newType === 'script') { + props['activiti:script'] = elementHelper.createElement('activiti:Script', {}, bo, bpmnFactory); + } + } + + var commands = []; + commands.push(cmdHelper.updateBusinessObject(element, bo, props)); + + if (hasServiceTaskLikeSupport) { + var connectors = extensionElementsHelper.getExtensionElements(bo, 'activiti:Connector'); + commands.push(map(connectors, function(connector) { + return extensionElementsHelper.removeEntry(bo, element, connector); + })); + + if (newType === 'connector') { + var extensionElements = bo.get('extensionElements'); + if (!extensionElements) { + extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory); + commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements })); + } + var connector = elementHelper.createElement('activiti:Connector', {}, extensionElements, bpmnFactory); + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [ connector ], + [] + )); + } + } + + return commands; + + } + })); + + return entries; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutput.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutput.js new file mode 100644 index 00000000..78dcd51d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutput.js @@ -0,0 +1,225 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var elementHelper = require('../../../../helper/ElementHelper'), + extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'), + inputOutputHelper = require('../../../../helper/InputOutputHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var extensionElementsEntry = require('./ExtensionElements'); + + +function getInputOutput(element, insideConnector) { + return inputOutputHelper.getInputOutput(element, insideConnector); +} + +function getConnector(element) { + return inputOutputHelper.getConnector(element); +} + +function getInputParameters(element, insideConnector) { + return inputOutputHelper.getInputParameters(element, insideConnector); +} + +function getOutputParameters(element, insideConnector) { + return inputOutputHelper.getOutputParameters(element, insideConnector); +} + +function getInputParameter(element, insideConnector, idx) { + return inputOutputHelper.getInputParameter(element, insideConnector, idx); +} + +function getOutputParameter(element, insideConnector, idx) { + return inputOutputHelper.getOutputParameter(element, insideConnector, idx); +} + + +function createElement(type, parent, factory, properties) { + return elementHelper.createElement(type, properties, parent, factory); +} + +function createInputOutput(parent, bpmnFactory, properties) { + return createElement('activiti:InputOutput', parent, bpmnFactory, properties); +} + +function createParameter(type, parent, bpmnFactory, properties) { + return createElement(type, parent, bpmnFactory, properties); +} + + +function ensureInputOutputSupported(element, insideConnector) { + return inputOutputHelper.isInputOutputSupported(element, insideConnector); +} + +function ensureOutparameterSupported(element, insideConnector) { + return inputOutputHelper.areOutputParametersSupported(element, insideConnector); +} + +module.exports = function(element, bpmnFactory, options, translate) { + + var TYPE_LABEL = { + 'activiti:Map': translate('Map'), + 'activiti:List': translate('List'), + 'activiti:Script': translate('Script') + }; + + options = options || {}; + + var insideConnector = !!options.insideConnector, + idPrefix = options.idPrefix || ''; + + var getSelected = function(element, node) { + var selection = (inputEntry && inputEntry.getSelected(element, node)) || { idx: -1 }; + + var parameter = getInputParameter(element, insideConnector, selection.idx); + if (!parameter && outputEntry) { + selection = outputEntry.getSelected(element, node); + parameter = getOutputParameter(element, insideConnector, selection.idx); + } + return parameter; + }; + + var result = { + getSelectedParameter: getSelected + }; + + var entries = result.entries = []; + + if (!ensureInputOutputSupported(element)) { + return result; + } + + var newElement = function(type, prop, factory) { + + return function(element, extensionElements, value) { + var commands = []; + + var inputOutput = getInputOutput(element, insideConnector); + if (!inputOutput) { + var parent = !insideConnector ? extensionElements : getConnector(element); + inputOutput = createInputOutput(parent, bpmnFactory, { + inputParameters: [], + outputParameters: [] + }); + + if (!insideConnector) { + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [ inputOutput ], + [] + )); + } else { + commands.push(cmdHelper.updateBusinessObject(element, parent, { inputOutput: inputOutput })); + } + } + + var newElem = createParameter(type, inputOutput, bpmnFactory, { name: value }); + commands.push(cmdHelper.addElementsTolist(element, inputOutput, prop, [ newElem ])); + + return commands; + }; + }; + + var removeElement = function(getter, prop, otherProp) { + return function(element, extensionElements, value, idx) { + var inputOutput = getInputOutput(element, insideConnector); + var parameter = getter(element, insideConnector, idx); + + var commands = []; + commands.push(cmdHelper.removeElementsFromList(element, inputOutput, prop, null, [ parameter ])); + + var firstLength = inputOutput.get(prop).length-1; + var secondLength = (inputOutput.get(otherProp) || []).length; + + if (!firstLength && !secondLength) { + + if (!insideConnector) { + commands.push(extensionElementsHelper.removeEntry(getBusinessObject(element), element, inputOutput)); + } else { + var connector = getConnector(element); + commands.push(cmdHelper.updateBusinessObject(element, connector, { inputOutput: undefined })); + } + + } + + return commands; + }; + }; + + var setOptionLabelValue = function(getter) { + return function(element, node, option, property, value, idx) { + var parameter = getter(element, insideConnector, idx); + + var suffix = 'Text'; + + var definition = parameter.get('definition'); + if (typeof definition !== 'undefined') { + var type = definition.$type; + suffix = TYPE_LABEL[type]; + } + + option.text = (value || '') + ' : ' + suffix; + }; + }; + + + // input parameters /////////////////////////////////////////////////////////////// + + var inputEntry = extensionElementsEntry(element, bpmnFactory, { + id: idPrefix + 'inputs', + label: translate('Input Parameters'), + modelProperty: 'name', + prefix: 'Input', + resizable: true, + + createExtensionElement: newElement('activiti:InputParameter', 'inputParameters'), + removeExtensionElement: removeElement(getInputParameter, 'inputParameters', 'outputParameters'), + + getExtensionElements: function(element) { + return getInputParameters(element, insideConnector); + }, + + onSelectionChange: function(element, node, event, scope) { + outputEntry && outputEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(getInputParameter) + + }); + entries.push(inputEntry); + + + // output parameters /////////////////////////////////////////////////////// + + if (ensureOutparameterSupported(element, insideConnector)) { + var outputEntry = extensionElementsEntry(element, bpmnFactory, { + id: idPrefix + 'outputs', + label: translate('Output Parameters'), + modelProperty: 'name', + prefix: 'Output', + resizable: true, + + createExtensionElement: newElement('activiti:OutputParameter', 'outputParameters'), + removeExtensionElement: removeElement(getOutputParameter, 'outputParameters', 'inputParameters'), + + getExtensionElements: function(element) { + return getOutputParameters(element, insideConnector); + }, + + onSelectionChange: function(element, node, event, scope) { + inputEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(getOutputParameter) + + }); + entries.push(outputEntry); + } + + return result; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutputParameter.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutputParameter.js new file mode 100644 index 00000000..fe9c4f9a --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/InputOutputParameter.js @@ -0,0 +1,364 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var elementHelper = require('../../../../helper/ElementHelper'), + inputOutputHelper = require('../../../../helper/InputOutputHelper'), + cmdHelper = require('../../../../helper/CmdHelper'), + utils = require('../../../../Utils'); + +var entryFactory = require('../../../../factory/EntryFactory'), + scriptImplementation = require('./Script'); + + +function createElement(type, parent, factory, properties) { + return elementHelper.createElement(type, properties, parent, factory); +} + +function isScript(elem) { + return is(elem, 'activiti:Script'); +} + +function isList(elem) { + return is(elem, 'activiti:List'); +} + +function isMap(elem) { + return is(elem, 'activiti:Map'); +} + +function ensureInputOutputSupported(element, insideConnector) { + return inputOutputHelper.isInputOutputSupported(element, insideConnector); +} + +module.exports = function(element, bpmnFactory, options, translate) { + + var typeInfo = { + 'activiti:Map': { + value: 'map', + label: translate('Map') + }, + 'activiti:List': { + value: 'list', + label: translate('List') + }, + 'activiti:Script': { + value: 'script', + label: translate('Script') + } + }; + + options = options || {}; + + var insideConnector = !!options.insideConnector, + idPrefix = options.idPrefix || ''; + + var getSelected = options.getSelectedParameter; + + if (!ensureInputOutputSupported(element, insideConnector)) { + return []; + } + + var entries = []; + + var isSelected = function(element, node) { + return getSelected(element, node); + }; + + + // parameter name //////////////////////////////////////////////////////// + + entries.push(entryFactory.validationAwareTextField({ + id: idPrefix + 'parameterName', + label: translate('Name'), + modelProperty: 'name', + + getProperty: function(element, node) { + return (getSelected(element, node) || {}).name; + }, + + setProperty: function(element, values, node) { + var param = getSelected(element, node); + return cmdHelper.updateBusinessObject(element, param, values); + }, + + validate: function(element, values, node) { + var bo = getSelected(element, node); + + var validation = {}; + if (bo) { + var nameValue = values.name; + + if (nameValue) { + if (utils.containsSpace(nameValue)) { + validation.name = translate('Name must not contain spaces'); + } + } else { + validation.name = translate('Parameter must have a name'); + } + } + + return validation; + }, + + hidden: function(element, node) { + return !isSelected(element, node); + } + })); + + + // parameter type ////////////////////////////////////////////////////// + + var selectOptions = [ + { value: 'text', name: translate('Text') }, + { value: 'script', name: translate('Script') }, + { value: 'list', name: translate('List') }, + { value: 'map', name: translate('Map') } + ]; + + entries.push(entryFactory.selectBox({ + id : idPrefix + 'parameterType', + label: translate('Type'), + selectOptions: selectOptions, + modelProperty: 'parameterType', + + get: function(element, node) { + var bo = getSelected(element, node); + + var parameterType = 'text'; + + if (typeof bo !== 'undefined') { + var definition = bo.get('definition'); + if (typeof definition !== 'undefined') { + var type = definition.$type; + parameterType = typeInfo[type].value; + } + } + + return { + parameterType: parameterType + }; + }, + + set: function(element, values, node) { + var bo = getSelected(element, node); + + var properties = { + value: undefined, + definition: undefined + }; + + var createParameterTypeElem = function(type) { + return createElement(type, bo, bpmnFactory); + }; + + var parameterType = values.parameterType; + + if (parameterType === 'script') { + properties.definition = createParameterTypeElem('activiti:Script'); + } + else if (parameterType === 'list') { + properties.definition = createParameterTypeElem('activiti:List'); + } + else if (parameterType === 'map') { + properties.definition = createParameterTypeElem('activiti:Map'); + } + + return cmdHelper.updateBusinessObject(element, bo, properties); + }, + + show: function(element, node) { + return isSelected(element, node); + } + + })); + + + // parameter value (type = text) /////////////////////////////////////////////////////// + + entries.push(entryFactory.textBox({ + id : idPrefix + 'parameterType-text', + label : translate('Value'), + modelProperty: 'value', + get: function(element, node) { + return { + value: (getSelected(element, node) || {}).value + }; + }, + + set: function(element, values, node) { + var param = getSelected(element, node); + values.value = values.value || undefined; + return cmdHelper.updateBusinessObject(element, param, values); + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && !bo.definition; + } + + })); + + + // parameter value (type = script) /////////////////////////////////////////////////////// + var script = scriptImplementation('scriptFormat', 'value', true, translate); + entries.push({ + id: idPrefix + 'parameterType-script', + html: '' + + script.template + + '', + get: function(element, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition) ? script.get(element, bo.definition) : {}; + }, + + set: function(element, values, node) { + var bo = getSelected(element, node); + var update = script.set(element, values); + return cmdHelper.updateBusinessObject(element, bo.definition, update); + }, + + validate: function(element, values, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition) ? script.validate(element, bo.definition) : {}; + }, + + isScript: function(element, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition); + }, + + script: script + + }); + + + // parameter value (type = list) /////////////////////////////////////////////////////// + + entries.push(entryFactory.table({ + id: idPrefix + 'parameterType-list', + modelProperties: [ 'value' ], + labels: [ translate('Value') ], + addLabel: translate('Add Value'), + + getElements: function(element, node) { + var bo = getSelected(element, node); + + if (bo && isList(bo.definition)) { + return bo.definition.items; + } + + return []; + }, + + updateElement: function(element, values, node, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + return cmdHelper.updateBusinessObject(element, item, values); + }, + + addElement: function(element, node) { + var bo = getSelected(element, node); + var newValue = createElement('activiti:Value', bo.definition, bpmnFactory, { value: undefined }); + return cmdHelper.addElementsTolist(element, bo.definition, 'items', [ newValue ]); + }, + + removeElement: function(element, node, idx) { + var bo = getSelected(element, node); + return cmdHelper.removeElementsFromList(element, bo.definition, 'items', null, [ bo.definition.items[idx] ]); + }, + + editable: function(element, node, prop, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + return !isMap(item) && !isList(item) && !isScript(item); + }, + + setControlValue: function(element, node, input, prop, value, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + + if (!isMap(item) && !isList(item) && !isScript(item)) { + input.value = value; + } else { + input.value = typeInfo[item.$type].label; + } + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && bo.definition && isList(bo.definition); + } + + })); + + + // parameter value (type = map) /////////////////////////////////////////////////////// + + entries.push(entryFactory.table({ + id: idPrefix + 'parameterType-map', + modelProperties: [ 'key', 'value' ], + labels: [ translate('Key'), translate('Value') ], + addLabel: translate('Add Entry'), + + getElements: function(element, node) { + var bo = getSelected(element, node); + + if (bo && isMap(bo.definition)) { + return bo.definition.entries; + } + + return []; + }, + + updateElement: function(element, values, node, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + + if (isMap(entry.definition) || isList(entry.definition) || isScript(entry.definition)) { + values = { + key: values.key + }; + } + + return cmdHelper.updateBusinessObject(element, entry, values); + }, + + addElement: function(element, node) { + var bo = getSelected(element, node); + var newEntry = createElement('activiti:Entry', bo.definition, bpmnFactory, { key: undefined, value: undefined }); + return cmdHelper.addElementsTolist(element, bo.definition, 'entries', [ newEntry ]); + }, + + removeElement: function(element, node, idx) { + var bo = getSelected(element, node); + return cmdHelper.removeElementsFromList(element, bo.definition, 'entries', null, [ bo.definition.entries[idx] ]); + }, + + editable: function(element, node, prop, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + return prop === 'key' || (!isMap(entry.definition) && !isList(entry.definition) && !isScript(entry.definition)); + }, + + setControlValue: function(element, node, input, prop, value, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + + if (prop === 'key' || (!isMap(entry.definition) && !isList(entry.definition) && !isScript(entry.definition))) { + input.value = value; + } else { + input.value = typeInfo[entry.definition.$type].label; + } + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && bo.definition && isMap(bo.definition); + } + + })); + + return entries; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobPriority.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobPriority.js new file mode 100644 index 00000000..f460f691 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobPriority.js @@ -0,0 +1,34 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var jobPriorityEntry = entryFactory.textField({ + id: 'jobPriority', + label: translate('Job Priority'), + modelProperty: 'jobPriority', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { + jobPriority: bo.get('activiti:jobPriority') + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:jobPriority': values.jobPriority || undefined + }); + } + + }); + + return [ jobPriorityEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobRetryTimeCycle.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobRetryTimeCycle.js new file mode 100644 index 00000000..a09b9d71 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/JobRetryTimeCycle.js @@ -0,0 +1,113 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var asyncCapableHelper = require('../../../../helper/AsyncCapableHelper'); + +var elementHelper = require('../../../../helper/ElementHelper'), + eventDefinitionHelper = require('../../../../helper/EventDefinitionHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +function isAsyncBefore(bo) { + return asyncCapableHelper.isAsyncBefore(bo); +} + +function isAsyncAfter(bo) { + return asyncCapableHelper.isAsyncAfter(bo); +} + +function getFailedJobRetryTimeCycle(bo) { + return asyncCapableHelper.getFailedJobRetryTimeCycle(bo); +} + +function removeFailedJobRetryTimeCycle(bo, element) { + return asyncCapableHelper.removeFailedJobRetryTimeCycle(bo, element); +} + +function createExtensionElements(parent, bpmnFactory) { + return elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, parent, bpmnFactory); +} + +function createFailedJobRetryTimeCycle(parent, bpmnFactory, cycle) { + return elementHelper.createElement('activiti:FailedJobRetryTimeCycle', { body: cycle }, parent, bpmnFactory); +} + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var idPrefix = options.idPrefix || '', + labelPrefix = options.labelPrefix || ''; + + var retryTimeCycleEntry = entryFactory.textField({ + id: idPrefix + 'retryTimeCycle', + label: labelPrefix + translate('Retry Time Cycle'), + modelProperty: 'cycle', + + get: function(element, node) { + var retryTimeCycle = getFailedJobRetryTimeCycle(getBusinessObject(element)); + var value = retryTimeCycle && retryTimeCycle.get('body'); + return { + cycle: value + }; + }, + + set: function(element, values, node) { + var newCycle = values.cycle; + var bo = getBusinessObject(element); + + if (newCycle === '' || typeof newCycle === 'undefined') { + // remove retry time cycle element(s) + return removeFailedJobRetryTimeCycle(bo, element); + } + + var retryTimeCycle = getFailedJobRetryTimeCycle(bo); + + if (!retryTimeCycle) { + // add new retry time cycle element + var commands = []; + + var extensionElements = bo.get('extensionElements'); + if (!extensionElements) { + extensionElements = createExtensionElements(bo, bpmnFactory); + commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements })); + } + + retryTimeCycle = createFailedJobRetryTimeCycle(extensionElements, bpmnFactory, newCycle); + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [ retryTimeCycle ], + [] + )); + + return commands; + } + + // update existing retry time cycle element + return cmdHelper.updateBusinessObject(element, retryTimeCycle, { body: newCycle }); + }, + + hidden: function(element) { + var bo = getBusinessObject(element); + + if (bo && (isAsyncBefore(bo) || isAsyncAfter(bo))) { + return false; + } + + if (is(element, 'bpmn:Event')) { + return !eventDefinitionHelper.getTimerEventDefinition(element); + } + + return true; + } + + }); + + return [ retryTimeCycleEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Listener.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Listener.js new file mode 100644 index 00000000..87accf11 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Listener.js @@ -0,0 +1,156 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var extensionElementsEntry = require('./ExtensionElements'), + extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'), + cmdHelper = require('../../../../helper/CmdHelper'), + elementHelper = require('../../../../helper/ElementHelper'), + ImplementationTypeHelper = require('../../../../helper/ImplementationTypeHelper'); + + +function getListeners(bo, type) { + return bo && extensionElementsHelper.getExtensionElements(bo, type) || []; +} + +var ACTIVITI_EXECUTION_LISTENER_ELEMENT = 'activiti:ExecutionListener'; +var ACTIVITI_TASK_LISTENER_ELEMENT = 'activiti:TaskListener'; + +module.exports = function(element, bpmnFactory, options, translate) { + + var LISTENER_TYPE_LABEL = { + class: translate('Java Class'), + expression: translate('Expression'), + delegateExpression: translate('Delegate Expression'), + script: translate('Script') + }; + + var bo; + + var result = { + getSelectedListener: getSelectedListener + }; + + var entries = result.entries = []; + + var isSequenceFlow = ImplementationTypeHelper.isSequenceFlow(element); + + function getSelectedListener(element, node) { + var selection = (executionListenerEntry && executionListenerEntry.getSelected(element, node)) || { idx: -1 }; + + var listener = getListeners(bo, ACTIVITI_EXECUTION_LISTENER_ELEMENT)[selection.idx]; + if (!listener && taskListenerEntry) { + selection = taskListenerEntry.getSelected(element, node); + listener = getListeners(bo, ACTIVITI_TASK_LISTENER_ELEMENT)[selection.idx]; + } + return listener; + } + + var setOptionLabelValue = function(type) { + return function(element, node, option, property, value, idx) { + var listeners = getListeners(bo, type); + var listener = listeners[idx]; + var listenerType = ImplementationTypeHelper.getImplementationType(listener); + + var event = (listener.get('event')) ? listener.get('event') : ''; + + var label = (event || '*') + ' : ' + (LISTENER_TYPE_LABEL[listenerType] || ''); + + option.text = label; + }; + }; + + var newElement = function(element, type, initialEvent) { + return function(element, extensionElements, value) { + var props = { + event: initialEvent, + class: '' + }; + + var newElem = elementHelper.createElement(type, props, extensionElements, bpmnFactory); + + return cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newElem ]); + }; + }; + + var removeElement = function(element, type) { + return function(element, extensionElements, value, idx) { + var listeners = getListeners(bo, type); + var listener = listeners[idx]; + if (listener) { + return extensionElementsHelper.removeEntry(bo, element, listener); + } + }; + }; + + + // Execution Listener + + if (is(element, 'bpmn:FlowElement') || is(element, 'bpmn:Process') || is(element, 'bpmn:Participant')) { + bo = getBusinessObject(element); + if (is(element, 'bpmn:Participant')) { + element = element.processRef; + bo = bo.get('processRef'); + } + + if (bo) { + + var executionListenerEntry = extensionElementsEntry(element, bpmnFactory, { + id : 'executionListeners', + label : translate('Execution Listener'), + modelProperty: 'name', + idGeneration: 'false', + reference: 'processRef', + + createExtensionElement: newElement(element, ACTIVITI_EXECUTION_LISTENER_ELEMENT, (isSequenceFlow) ? 'take' : 'start'), + removeExtensionElement: removeElement(element, ACTIVITI_EXECUTION_LISTENER_ELEMENT), + + getExtensionElements: function(element) { + return getListeners(bo, ACTIVITI_EXECUTION_LISTENER_ELEMENT); + }, + + onSelectionChange: function(element, node, event, scope) { + taskListenerEntry && taskListenerEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(ACTIVITI_EXECUTION_LISTENER_ELEMENT) + + }); + entries.push(executionListenerEntry); + + } + } + + + // Task Listener + + if (is(element, 'bpmn:UserTask')) { + bo = getBusinessObject(element); + + var taskListenerEntry = extensionElementsEntry(element, bpmnFactory, { + id : 'taskListeners', + label : translate('Task Listener'), + modelProperty: 'name', + idGeneration: 'false', + + createExtensionElement: newElement(element, ACTIVITI_TASK_LISTENER_ELEMENT, 'create'), + removeExtensionElement: removeElement(element, ACTIVITI_TASK_LISTENER_ELEMENT), + + getExtensionElements: function(element) { + return getListeners(bo, ACTIVITI_TASK_LISTENER_ELEMENT); + }, + + onSelectionChange: function(element, node, event, scope) { + executionListenerEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(ACTIVITI_TASK_LISTENER_ELEMENT) + + }); + entries.push(taskListenerEntry); + } + + return result; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/MultiInstanceLoopCharacteristics.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/MultiInstanceLoopCharacteristics.js new file mode 100644 index 00000000..a0e406a5 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/MultiInstanceLoopCharacteristics.js @@ -0,0 +1,290 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + escapeHTML = require('../../../../Utils').escapeHTML; + + +var entryFactory = require('../../../../factory/EntryFactory'); + +var elementHelper = require('../../../../helper/ElementHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var domClasses = require('min-dom').classes; + +/** + * Get a property value of the loop characteristics. + * + * @param {djs.model.Base} element + * @param {string} propertyName + * + * @return {any} the property value + */ +function getProperty(element, propertyName) { + var loopCharacteristics = getLoopCharacteristics(element); + return loopCharacteristics && loopCharacteristics.get(propertyName); +} + +/** + * Get the body of a given expression. + * + * @param {ModdleElement} expression + * + * @return {string} the body (value) of the expression + */ +function getBody(expression) { + return expression && expression.get('body'); +} + + +/** + * Get the loop characteristics of an element. + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} the loop characteristics + */ +function getLoopCharacteristics(element) { + var bo = getBusinessObject(element); + return bo.loopCharacteristics; +} + +/** + * Get the loop cardinality of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} an expression representing the loop cardinality + */ +function getLoopCardinality(element) { + return getProperty(element, 'loopCardinality'); +} + +/** + * Get the loop cardinality value of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {string} the loop cardinality value + */ +function getLoopCardinalityValue(element) { + var loopCardinality = getLoopCardinality(element); + return getBody(loopCardinality); +} + +/** + * Get the completion condition of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} an expression representing the completion condition + */ +function getCompletionCondition(element) { + return getProperty(element, 'completionCondition'); +} + +/** + * Get the completion condition value of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {string} the completion condition value + */ +function getCompletionConditionValue(element) { + var completionCondition = getCompletionCondition(element); + return getBody(completionCondition); +} + +/** + * Get the 'activiti:collection' attribute value of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {string} the 'activiti:collection' value + */ +function getCollection(element) { + return getProperty(element, 'activiti:collection'); +} + +/** + * Get the 'activiti:elementVariable' attribute value of the loop characteristics. + * + * @param {djs.model.Base} element + * + * @return {string} the 'activiti:elementVariable' value + */ +function getElementVariable(element) { + return getProperty(element, 'activiti:elementVariable'); +} + + +/** + * Creates 'bpmn:FormalExpression' element. + * + * @param {ModdleElement} parent + * @param {string} body + * @param {BpmnFactory} bpmnFactory + * + * @result {ModdleElement} a formal expression + */ +function createFormalExpression(parent, body, bpmnFactory) { + return elementHelper.createElement('bpmn:FormalExpression', { body: body }, parent, bpmnFactory); +} + +/** + * Updates a specific formal expression of the loop characteristics. + * + * @param {djs.model.Base} element + * @param {string} propertyName + * @param {string} newValue + * @param {BpmnFactory} bpmnFactory + */ +function updateFormalExpression(element, propertyName, newValue, bpmnFactory) { + var loopCharacteristics = getLoopCharacteristics(element); + + var expressionProps = {}; + + if (!newValue) { + // remove formal expression + expressionProps[propertyName] = undefined; + return cmdHelper.updateBusinessObject(element, loopCharacteristics, expressionProps); + } + + var existingExpression = loopCharacteristics.get(propertyName); + + if (!existingExpression) { + // add formal expression + expressionProps[propertyName] = createFormalExpression(loopCharacteristics, newValue, bpmnFactory); + return cmdHelper.updateBusinessObject(element, loopCharacteristics, expressionProps); + } + + // edit existing formal expression + return cmdHelper.updateBusinessObject(element, existingExpression, { + body: newValue + }); +} + + +module.exports = function(element, bpmnFactory, translate) { + + var entries = []; + + // error message ///////////////////////////////////////////////////////////////// + + entries.push({ + id: 'multiInstance-errorMessage', + html: '' + + ' ' + + escapeHTML(translate('Must provide either loop cardinality or collection')) + + '', + + isValid: function(element, node, notification, scope) { + var loopCharacteristics = getLoopCharacteristics(element); + + var isValid = true; + if (loopCharacteristics) { + var loopCardinality = getLoopCardinalityValue(element); + var collection = getCollection(element); + + isValid = !loopCardinality && !collection; + } + + domClasses(node).toggle('bpp-hidden', !isValid); + domClasses(notification).toggle('bpp-error-message', isValid); + + return isValid; + } + }); + + // loop cardinality ////////////////////////////////////////////////////////////// + + entries.push(entryFactory.textField({ + id: 'multiInstance-loopCardinality', + label: translate('Loop Cardinality'), + modelProperty: 'loopCardinality', + + get: function(element, node) { + return { + loopCardinality: getLoopCardinalityValue(element) + }; + }, + + set: function(element, values) { + return updateFormalExpression(element, 'loopCardinality', values.loopCardinality, bpmnFactory); + } + })); + + + // collection ////////////////////////////////////////////////////////////////// + + entries.push(entryFactory.textField({ + id: 'multiInstance-collection', + label: translate('Collection'), + modelProperty: 'collection', + + get: function(element, node) { + return { + collection: getCollection(element) + }; + }, + + set: function(element, values) { + var loopCharacteristics = getLoopCharacteristics(element); + return cmdHelper.updateBusinessObject(element, loopCharacteristics, { + 'activiti:collection': values.collection || undefined + }); + }, + + validate: function(element, values, node) { + var collection = getCollection(element); + var elementVariable = getElementVariable(element); + + if (!collection && elementVariable) { + return { collection : 'Must provide a value' }; + } + } + })); + + + // element variable //////////////////////////////////////////////////////////// + + entries.push(entryFactory.textField({ + id: 'multiInstance-elementVariable', + label: translate('Element Variable'), + modelProperty: 'elementVariable', + + get: function(element, node) { + return { + elementVariable: getElementVariable(element) + }; + }, + + set: function(element, values) { + var loopCharacteristics = getLoopCharacteristics(element); + return cmdHelper.updateBusinessObject(element, loopCharacteristics, { + 'activiti:elementVariable': values.elementVariable || undefined + }); + } + })); + + + // Completion Condition ////////////////////////////////////////////////////// + + entries.push(entryFactory.textField({ + id: 'multiInstance-completionCondition', + label: translate('Completion Condition'), + modelProperty: 'completionCondition', + + get: function(element) { + return { + completionCondition: getCompletionConditionValue(element) + }; + }, + + set: function(element, values) { + return updateFormalExpression(element, 'completionCondition', values.completionCondition, bpmnFactory); + } + })); + + return entries; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Properties.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Properties.js new file mode 100644 index 00000000..cc3d5353 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Properties.js @@ -0,0 +1,209 @@ +'use strict'; + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is; + +var factory = require('../../../../factory/EntryFactory'); + +var elementHelper = require('../../../../helper/ElementHelper'), + extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'), + cmdHelper = require('../../../../helper/CmdHelper'), + utils = require('../../../../Utils'); + +var assign = require('lodash/assign'), + forEach = require('lodash/forEach'), + find = require('lodash/find'); + +function generatePropertyId() { + return utils.nextId('Property_'); +} + +/** + * Get all activiti:property objects for a specific business object + * + * @param {ModdleElement} parent + * + * @return {Array} a list of activiti:property objects + */ +function getPropertyValues(parent) { + var properties = parent && getPropertiesElement(parent); + if (properties && properties.values) { + return properties.values; + } + return []; +} + +/** + * Get all activiti:Properties object for a specific business object + * + * @param {ModdleElement} parent + * + * @return {ModdleElement} a activiti:Properties object + */ +function getPropertiesElement(element) { + if (!isExtensionElements(element)) { + return element.properties; + } else { + return getPropertiesElementInsideExtensionElements(element); + } +} + +/** + * Get first activiti:Properties object for a specific bpmn:ExtensionElements + * business object. + * + * @param {ModdleElement} extensionElements + * + * @return {ModdleElement} a activiti:Properties object + */ +function getPropertiesElementInsideExtensionElements(extensionElements) { + return find(extensionElements.values, function(elem) { + return is(elem, 'activiti:Properties'); + }); +} + +/** + * Returns true, if the given business object is a bpmn:ExtensionElements. + * + * @param {ModdleElement} element + * + * @return {boolean} a boolean value + */ +function isExtensionElements(element) { + return is(element, 'bpmn:ExtensionElements'); +} + +/** + * Create a activiti:property entry using tableEntryFactory + * + * @param {djs.model.Base} element + * @param {BpmnFactory} bpmnFactory + * @param {Object} options + * @param {string} options.id + * @param {Array} options.modelProperties + * @param {Array} options.labels + * @param {function} options.getParent Gets the parent business object + * @param {function} options.show Indicate when the entry will be shown, should return boolean + */ +module.exports = function(element, bpmnFactory, options, translate) { + + var getParent = options.getParent; + + var modelProperties = options.modelProperties, + createParent = options.createParent; + + var bo = getBusinessObject(element); + if (is(element, 'bpmn:Participant')) { + bo = bo.get('processRef'); + } + + // build properties group only when the participant have a processRef + if (!bo) { + return; + } + + assign(options, { + addLabel: translate('Add Property'), + getElements: function(element, node) { + var parent = getParent(element, node, bo); + return getPropertyValues(parent); + }, + addElement: function(element, node) { + var commands = [], + parent = getParent(element, node, bo); + + if (!parent && typeof createParent === 'function') { + var result = createParent(element, bo); + parent = result.parent; + commands.push(result.cmd); + } + + var properties = getPropertiesElement(parent); + if (!properties) { + properties = elementHelper.createElement('activiti:Properties', {}, parent, bpmnFactory); + + if (!isExtensionElements(parent)) { + commands.push(cmdHelper.updateBusinessObject(element, parent, { 'properties': properties })); + } else { + commands.push(cmdHelper.addAndRemoveElementsFromList( + element, + parent, + 'values', + 'extensionElements', + [ properties ], + [] + )); + } + } + + var propertyProps = {}; + forEach(modelProperties, function(prop) { + propertyProps[prop] = undefined; + }); + + // create id if necessary + if (modelProperties.indexOf('id') >= 0) { + propertyProps.id = generatePropertyId(); + } + + var property = elementHelper.createElement('activiti:Property', propertyProps, properties, bpmnFactory); + commands.push(cmdHelper.addElementsTolist(element, properties, 'values', [ property ])); + + return commands; + }, + updateElement: function(element, value, node, idx) { + var parent = getParent(element, node, bo), + property = getPropertyValues(parent)[idx]; + + forEach(modelProperties, function(prop) { + value[prop] = value[prop] || undefined; + }); + + return cmdHelper.updateBusinessObject(element, property, value); + }, + validate: function(element, value, node, idx) { + // validate id if necessary + if (modelProperties.indexOf('id') >= 0) { + + var parent = getParent(element, node, bo), + properties = getPropertyValues(parent), + property = properties[idx]; + + if (property) { + // check if id is valid + var validationError = utils.isIdValid(property, value.id, translate); + + if (validationError) { + return { id: validationError }; + } + } + } + }, + removeElement: function(element, node, idx) { + var commands = [], + parent = getParent(element, node, bo), + properties = getPropertiesElement(parent), + propertyValues = getPropertyValues(parent), + currentProperty = propertyValues[idx]; + + commands.push(cmdHelper.removeElementsFromList(element, properties, 'values', null, [ currentProperty ])); + + if (propertyValues.length === 1) { + // remove activiti:properties if the last existing property has been removed + if (!isExtensionElements(parent)) { + commands.push(cmdHelper.updateBusinessObject(element, parent, { properties: undefined })); + } else { + forEach(parent.values, function(value) { + if (is(value, 'activiti:Properties')) { + commands.push(extensionElementsHelper.removeEntry(bo, element, value)); + } + }); + } + } + + return commands; + } + }); + + return factory.table(options); +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ResultVariable.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ResultVariable.js new file mode 100644 index 00000000..fb983e44 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/ResultVariable.js @@ -0,0 +1,53 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var assign = require('lodash/assign'); + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject, + hideResultVariable = options.hideResultVariable, + id = options.id || 'resultVariable'; + + + var resultVariableEntry = entryFactory.textField({ + id: id, + label: translate('Result Variable'), + modelProperty: 'resultVariable', + + get: function(element, node) { + var bo = getBusinessObject(element); + return { resultVariable: bo.get('activiti:resultVariable') }; + }, + + set: function(element, values, node) { + var bo = getBusinessObject(element); + + var resultVariable = values.resultVariable || undefined; + + var props = { + 'activiti:resultVariable': resultVariable + }; + + if (is(bo, 'activiti:DmnCapable') && !resultVariable) { + props = assign({ 'activiti:mapDecisionResult': 'resultList' }, props); + } + + return cmdHelper.updateBusinessObject(element, bo, props); + }, + + hidden: function(element, node) { + if (typeof hideResultVariable === 'function') { + return hideResultVariable.apply(resultVariableEntry, arguments); + } + } + + }); + + return [ resultVariableEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Script.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Script.js new file mode 100644 index 00000000..1969cdd4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Script.js @@ -0,0 +1,173 @@ +'use strict'; + +var domQuery = require('min-dom').query, + escapeHTML = require('../../../../Utils').escapeHTML, + utils = require('../../../../Utils'); + + +function getScriptType(node) { + return utils.selectedType('select[name=scriptType]', node.parentElement); +} + + +module.exports = function(scriptLanguagePropName, scriptValuePropName, isFormatRequired, translate) { + + return { + template: + '' + + '' + escapeHTML(translate('Script Format')) + '' + + '' + + '' + + '' + + 'X' + + '' + + '' + + '' + + + '' + + '' + escapeHTML(translate('Script Type')) + '' + + '' + + '' + + '' + escapeHTML(translate('Inline Script')) + '' + + '' + escapeHTML(translate('External Resource')) + '' + + '' + + '' + + '' + + + '' + + '' + escapeHTML(translate('Resource')) + '' + + '' + + '' + + '' + + 'X' + + '' + + '' + + '' + + + '' + + '' + escapeHTML(translate('Script')) + '' + + '' + + '' + + ''+ + '', + + get: function(element, bo) { + var values = {}; + + // read values from xml: + var boScriptResource = bo.get('activiti:resource'), + boScript = bo.get(scriptValuePropName), + boScriptFormat = bo.get(scriptLanguagePropName); + + if (typeof boScriptResource !== 'undefined') { + values.scriptResourceValue = boScriptResource; + values.scriptType = 'scriptResource'; + } else { + values.scriptValue = boScript; + values.scriptType = 'script'; + } + + values.scriptFormat = boScriptFormat; + + return values; + }, + + set: function(element, values, containerElement) { + var scriptFormat = values.scriptFormat, + scriptType = values.scriptType, + scriptResourceValue = values.scriptResourceValue, + scriptValue = values.scriptValue; + + // init update + var update = { + 'activiti:resource': undefined + }; + update[scriptValuePropName] = undefined; + update[scriptLanguagePropName] = undefined; + + if (isFormatRequired) { + // always set language + update[scriptLanguagePropName] = scriptFormat || ''; + } else + // set language only when scriptFormat has a value + if (scriptFormat !== '') { + update[scriptLanguagePropName] = scriptFormat; + } + + // set either inline script or resource + if ('scriptResource' === scriptType) { + update['activiti:resource'] = scriptResourceValue || ''; + } else { + update[scriptValuePropName] = scriptValue || ''; + } + + return update; + }, + + validate: function(element, values) { + var validationResult = {}; + + if (values.scriptType === 'script' && !values.scriptValue) { + validationResult.scriptValue = translate('Must provide a value'); + } + + if (values.scriptType === 'scriptResource' && !values.scriptResourceValue) { + validationResult.scriptResourceValue = translate('Must provide a value'); + } + + if (isFormatRequired && (!values.scriptFormat || values.scriptFormat.length === 0)) { + validationResult.scriptFormat = translate('Must provide a value'); + } + + return validationResult; + }, + + clearScriptFormat: function(element, inputNode, btnNode, scopeNode) { + domQuery('input[name=scriptFormat]', scopeNode).value=''; + + return true; + }, + + canClearScriptFormat: function(element, inputNode, btnNode, scopeNode) { + var input = domQuery('input[name=scriptFormat]', scopeNode); + + return input.value !== ''; + }, + + clearScriptResource: function(element, inputNode, btnNode, scopeNode) { + domQuery('input[name=scriptResourceValue]', scopeNode).value=''; + + return true; + }, + + canClearScriptResource: function(element, inputNode, btnNode, scopeNode) { + var input = domQuery('input[name=scriptResourceValue]', scopeNode); + + return input.value !== ''; + }, + + clearScript: function(element, inputNode, btnNode, scopeNode) { + domQuery('textarea[name=scriptValue]', scopeNode).value=''; + + return true; + }, + + canClearScript: function(element, inputNode, btnNode, scopeNode) { + var input = domQuery('textarea[name=scriptValue]', scopeNode); + + return input.value !== ''; + }, + + isScriptResource: function(element, inputNode, btnNode, scopeNode) { + var scriptType = getScriptType(scopeNode); + return scriptType === 'scriptResource'; + }, + + isScript: function(element, inputNode, btnNode, scopeNode) { + var scriptType = getScriptType(scopeNode); + return scriptType === 'script'; + } + + }; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Tasklist.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Tasklist.js new file mode 100644 index 00000000..ad374806 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/activiti/parts/implementation/Tasklist.js @@ -0,0 +1,37 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +module.exports = function(element, bpmnFactory, options, translate) { + + var getBusinessObject = options.getBusinessObject; + + var isStartableInTasklistEntry = entryFactory.checkbox({ + id: 'isStartableInTasklist', + label: translate('Startable'), + modelProperty: 'isStartableInTasklist', + + get: function(element, node) { + var bo = getBusinessObject(element); + var isStartableInTasklist = bo.get('activiti:isStartableInTasklist'); + + return { + isStartableInTasklist: isStartableInTasklist ? isStartableInTasklist : '' + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + return cmdHelper.updateBusinessObject(element, bo, { + 'activiti:isStartableInTasklist': !!values.isStartableInTasklist + }); + } + + }); + + return [ + isStartableInTasklistEntry + ]; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/BpmnPropertiesProvider.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/BpmnPropertiesProvider.js new file mode 100644 index 00000000..c380df9b --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/BpmnPropertiesProvider.js @@ -0,0 +1,84 @@ +'use strict'; + + +var inherits = require('inherits'); + +var PropertiesActivator = require('../../PropertiesActivator'); + +var processProps = require('./parts/ProcessProps'), + eventProps = require('./parts/EventProps'), + linkProps = require('./parts/LinkProps'), + documentationProps = require('./parts/DocumentationProps'), + idProps = require('./parts/IdProps'), + nameProps = require('./parts/NameProps'), + executableProps = require('./parts/ExecutableProps'); + +function createGeneralTabGroups( + element, canvas, bpmnFactory, + elementRegistry, translate) { + + var generalGroup = { + id: 'general', + label: translate('General'), + entries: [] + }; + idProps(generalGroup, element, translate); + nameProps(generalGroup, element, bpmnFactory, canvas, translate); + processProps(generalGroup, element, translate); + executableProps(generalGroup, element, translate); + + var detailsGroup = { + id: 'details', + label: translate('Details'), + entries: [] + }; + linkProps(detailsGroup, element, translate); + eventProps(detailsGroup, element, bpmnFactory, elementRegistry, translate); + + var documentationGroup = { + id: 'documentation', + label: translate('Documentation'), + entries: [] + }; + + documentationProps(documentationGroup, element, bpmnFactory, translate); + + return [ + generalGroup, + detailsGroup, + documentationGroup + ]; + +} + +function BpmnPropertiesProvider( + eventBus, canvas, bpmnFactory, elementRegistry, translate) { + + PropertiesActivator.call(this, eventBus); + + this.getTabs = function(element) { + + var generalTab = { + id: 'general', + label: translate('General'), + groups: createGeneralTabGroups( + element, canvas, bpmnFactory, elementRegistry, translate) + }; + + return [ + generalTab + ]; + }; +} + +BpmnPropertiesProvider.$inject = [ + 'eventBus', + 'canvas', + 'bpmnFactory', + 'elementRegistry', + 'translate' +]; + +inherits(BpmnPropertiesProvider, PropertiesActivator); + +module.exports = BpmnPropertiesProvider; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/index.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/index.js new file mode 100644 index 00000000..8e045590 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/index.js @@ -0,0 +1,4 @@ +module.exports = { + __init__: [ 'propertiesProvider' ], + propertiesProvider: [ 'type', require('./BpmnPropertiesProvider') ] +}; \ No newline at end of file diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/DocumentationProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/DocumentationProps.js new file mode 100644 index 00000000..f742a3da --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/DocumentationProps.js @@ -0,0 +1,73 @@ +'use strict'; + +var entryFactory = require('../../../factory/EntryFactory'), + cmdHelper = require('../../../helper/CmdHelper'); + +var ModelUtil = require('bpmn-js/lib/util/ModelUtil'), + is = ModelUtil.is, + getBusinessObject = ModelUtil.getBusinessObject; + + +module.exports = function(group, element, bpmnFactory, translate) { + + var getValue = function(businessObject) { + return function(element) { + var documentations = businessObject && businessObject.get('documentation'), + text = (documentations && documentations.length > 0) ? documentations[0].text : ''; + + return { documentation: text }; + }; + }; + + var setValue = function(businessObject) { + return function(element, values) { + var newObjectList = []; + + if (typeof values.documentation !== 'undefined' && values.documentation !== '') { + newObjectList.push(bpmnFactory.create('bpmn:Documentation', { + text: values.documentation + })); + } + + return cmdHelper.setList(element, businessObject, 'documentation', newObjectList); + }; + }; + + // Element Documentation + var elementDocuEntry = entryFactory.textBox({ + id: 'documentation', + label: translate('Element Documentation'), + modelProperty: 'documentation' + }); + + elementDocuEntry.set = setValue(getBusinessObject(element)); + + elementDocuEntry.get = getValue(getBusinessObject(element)); + + group.entries.push(elementDocuEntry); + + + var processRef; + + // Process Documentation when having a Collaboration Diagram + if (is(element, 'bpmn:Participant')) { + + processRef = getBusinessObject(element).processRef; + + // do not show for collapsed Pools/Participants + if (processRef) { + var processDocuEntry = entryFactory.textBox({ + id: 'process-documentation', + label: translate('Process Documentation'), + modelProperty: 'documentation' + }); + + processDocuEntry.set = setValue(processRef); + + processDocuEntry.get = getValue(processRef); + + group.entries.push(processDocuEntry); + } + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/EventProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/EventProps.js new file mode 100644 index 00000000..97cc8db4 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/EventProps.js @@ -0,0 +1,150 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + isAny = require('bpmn-js/lib/features/modeling/util/ModelingUtil').isAny, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + eventDefinitionHelper = require('../../../helper/EventDefinitionHelper'); + +var forEach = require('lodash/forEach'); + +var message = require('./implementation/MessageEventDefinition'), + signal = require('./implementation/SignalEventDefinition'), + error = require('./implementation/ErrorEventDefinition'), + escalation = require('./implementation/EscalationEventDefinition'), + timer = require('./implementation/TimerEventDefinition'), + compensation = require('./implementation/CompensateEventDefinition'), + condition = require('./implementation/ConditionalEventDefinition'); + + +module.exports = function(group, element, bpmnFactory, elementRegistry, translate) { + var events = [ + 'bpmn:StartEvent', + 'bpmn:EndEvent', + 'bpmn:IntermediateThrowEvent', + 'bpmn:BoundaryEvent', + 'bpmn:IntermediateCatchEvent' + ]; + + // Message and Signal Event Definition + forEach(events, function(event) { + if (is(element, event)) { + + var messageEventDefinition = eventDefinitionHelper.getMessageEventDefinition(element), + signalEventDefinition = eventDefinitionHelper.getSignalEventDefinition(element); + + if (messageEventDefinition) { + message(group, element, bpmnFactory, messageEventDefinition, translate); + } + + if (signalEventDefinition) { + signal(group, element, bpmnFactory, signalEventDefinition, translate); + } + + } + }); + + // Special Case: Receive Task + if (is(element, 'bpmn:ReceiveTask')) { + message(group, element, bpmnFactory, getBusinessObject(element), translate); + } + + // Error Event Definition + var errorEvents = [ + 'bpmn:StartEvent', + 'bpmn:BoundaryEvent', + 'bpmn:EndEvent' + ]; + + forEach(errorEvents, function(event) { + if (is(element, event)) { + + var errorEventDefinition = eventDefinitionHelper.getErrorEventDefinition(element); + + if (errorEventDefinition) { + + error(group, element, bpmnFactory, errorEventDefinition, translate); + } + } + }); + + // Escalation Event Definition + var escalationEvents = [ + 'bpmn:StartEvent', + 'bpmn:BoundaryEvent', + 'bpmn:IntermediateThrowEvent', + 'bpmn:EndEvent' + ]; + + forEach(escalationEvents, function(event) { + if (is(element, event)) { + + var showEscalationCodeVariable = is(element, 'bpmn:StartEvent') || is(element, 'bpmn:BoundaryEvent'); + + // get business object + var escalationEventDefinition = eventDefinitionHelper.getEscalationEventDefinition(element); + + if (escalationEventDefinition) { + escalation(group, element, bpmnFactory, escalationEventDefinition, showEscalationCodeVariable, + translate); + } + } + + }); + + // Timer Event Definition + var timerEvents = [ + 'bpmn:StartEvent', + 'bpmn:BoundaryEvent', + 'bpmn:IntermediateCatchEvent' + ]; + + forEach(timerEvents, function(event) { + if (is(element, event)) { + + // get business object + var timerEventDefinition = eventDefinitionHelper.getTimerEventDefinition(element); + + if (timerEventDefinition) { + timer(group, element, bpmnFactory, timerEventDefinition, translate); + } + } + }); + + // Compensate Event Definition + var compensationEvents = [ + 'bpmn:EndEvent', + 'bpmn:IntermediateThrowEvent' + ]; + + forEach(compensationEvents, function(event) { + if (is(element, event)) { + + // get business object + var compensateEventDefinition = eventDefinitionHelper.getCompensateEventDefinition(element); + + if (compensateEventDefinition) { + compensation(group, element, bpmnFactory, compensateEventDefinition, elementRegistry, translate); + } + } + }); + + + // Conditional Event Definition + var conditionalEvents = [ + 'bpmn:StartEvent', + 'bpmn:BoundaryEvent', + 'bpmn:IntermediateThrowEvent', + 'bpmn:IntermediateCatchEvent' + ]; + + if (isAny(element, conditionalEvents)) { + + // get business object + var conditionalEventDefinition = eventDefinitionHelper.getConditionalEventDefinition(element); + + if (conditionalEventDefinition) { + condition(group, element, bpmnFactory, conditionalEventDefinition, elementRegistry, translate); + } + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ExecutableProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ExecutableProps.js new file mode 100644 index 00000000..e3dc6f55 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ExecutableProps.js @@ -0,0 +1,40 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var entryFactory = require('../../../factory/EntryFactory'); + +var participantHelper = require('../../../helper/ParticipantHelper'); + +module.exports = function(group, element, translate) { + + var bo = getBusinessObject(element); + + if (!bo) { + return; + } + + if (is(element, 'bpmn:Process') || (is(element, 'bpmn:Participant') && bo.get('processRef'))) { + + var executableEntry = entryFactory.checkbox({ + id: 'process-is-executable', + label: translate('Executable'), + modelProperty: 'isExecutable' + }); + + // in participants we have to change the default behavior of set and get + if (is(element, 'bpmn:Participant')) { + executableEntry.get = function(element) { + return participantHelper.getProcessBusinessObject(element, 'isExecutable'); + }; + + executableEntry.set = function(element, values) { + return participantHelper.modifyProcessBusinessObject(element, 'isExecutable', values); + }; + } + + group.entries.push(executableEntry); + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/IdProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/IdProps.js new file mode 100644 index 00000000..c929814f --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/IdProps.js @@ -0,0 +1,38 @@ +'use strict'; + +var entryFactory = require('../../../factory/EntryFactory'), + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + utils = require('../../../Utils'), + cmdHelper = require('../../../helper/CmdHelper'); + +module.exports = function(group, element, translate, options) { + + var description = options && options.description; + + // Id + group.entries.push(entryFactory.validationAwareTextField({ + id: 'id', + label: translate('Id'), + description: description && translate(description), + modelProperty: 'id', + getProperty: function(element) { + return getBusinessObject(element).id; + }, + setProperty: function(element, properties) { + + element = element.labelTarget || element; + + return cmdHelper.updateProperties(element, properties); + }, + validate: function(element, values) { + var idValue = values.id; + + var bo = getBusinessObject(element); + + var idError = utils.isIdValid(bo, idValue, translate); + + return idError ? { id: idError } : {}; + } + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/LinkProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/LinkProps.js new file mode 100644 index 00000000..b57248d7 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/LinkProps.js @@ -0,0 +1,57 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + entryFactory = require('../../../factory/EntryFactory'), + cmdHelper = require('../../../helper/CmdHelper'); + +var forEach = require('lodash/forEach'); + +function getLinkEventDefinition(element) { + + var bo = getBusinessObject(element); + + var linkEventDefinition = null; + if (bo.eventDefinitions) { + forEach(bo.eventDefinitions, function(eventDefinition) { + if (is(eventDefinition, 'bpmn:LinkEventDefinition')) { + linkEventDefinition = eventDefinition; + } + }); + } + + return linkEventDefinition; +} + +module.exports = function(group, element, translate) { + var linkEvents = [ 'bpmn:IntermediateThrowEvent', 'bpmn:IntermediateCatchEvent' ]; + + forEach(linkEvents, function(event) { + if (is(element, event)) { + + var linkEventDefinition = getLinkEventDefinition(element); + + if (linkEventDefinition) { + var entry = entryFactory.textField({ + id: 'link-event', + label: translate('Link Name'), + modelProperty: 'link-name' + }); + + entry.get = function() { + return { 'link-name': linkEventDefinition.get('name') }; + }; + + entry.set = function(element, values) { + var newProperties = { + name: values['link-name'] + }; + return cmdHelper.updateBusinessObject(element, linkEventDefinition, newProperties); + }; + + group.entries.push(entry); + } + } + }); +}; + diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/NameProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/NameProps.js new file mode 100644 index 00000000..36363253 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/NameProps.js @@ -0,0 +1,63 @@ +'use strict'; + +var nameEntryFactory = require('./implementation/Name'), + createCategoryValue = require('../../../helper/CategoryHelper').createCategoryValue, + is = require('bpmn-js/lib/util/ModelUtil').is, + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +module.exports = function(group, element, bpmnFactory, canvas, translate) { + + function initializeCategory(semantic) { + var rootElement = canvas.getRootElement(), + definitions = getBusinessObject(rootElement).$parent, + categoryValue = createCategoryValue(definitions, bpmnFactory); + + semantic.categoryValueRef = categoryValue; + + } + + function setGroupName(element, values) { + var bo = getBusinessObject(element), + categoryValueRef = bo.categoryValueRef; + + if (!categoryValueRef) { + initializeCategory(bo); + } + + // needs direct call to update categoryValue properly + return { + cmd: 'element.updateLabel', + context: { + element: element, + newLabel: values.categoryValue + } + }; + } + + function getGroupName(element) { + var bo = getBusinessObject(element), + value = (bo.categoryValueRef || {}).value; + + return { categoryValue: value }; + } + + if (!is(element, 'bpmn:Collaboration')) { + + var options; + if (is(element, 'bpmn:TextAnnotation')) { + options = { modelProperty: 'text', label: translate('Text') }; + } else if (is(element, 'bpmn:Group')) { + options = { + modelProperty: 'categoryValue', + label: translate('Category Value'), + get: getGroupName, + set: setGroupName + }; + } + + // name + group.entries = group.entries.concat(nameEntryFactory(element, options, translate)); + + } + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ProcessProps.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ProcessProps.js new file mode 100644 index 00000000..4d144e2a --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/ProcessProps.js @@ -0,0 +1,71 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is, + entryFactory = require('../../../factory/EntryFactory'), + participantHelper = require('../../../helper/ParticipantHelper'), + getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + nameEntryFactory = require('./implementation/Name'), + utils = require('../../../Utils'); + +module.exports = function(group, element, translate, options) { + var businessObject = getBusinessObject(element); + + var processIdDescription = options && options.processIdDescription; + + if (is(element, 'bpmn:Process') || (is(element, 'bpmn:Participant') && businessObject.get('processRef'))) { + + /** + * processId + */ + if (is(element, 'bpmn:Participant')) { + var idEntry = entryFactory.validationAwareTextField({ + id: 'process-id', + label: translate('Process Id'), + description: processIdDescription && translate(processIdDescription), + modelProperty: 'processId' + }); + + // in participants we have to change the default behavior of set and get + idEntry.get = function(element) { + var properties = participantHelper.getProcessBusinessObject(element, 'id'); + return { processId: properties.id }; + }; + + idEntry.set = function(element, values) { + return participantHelper.modifyProcessBusinessObject(element, 'id', { id: values.processId }); + }; + + idEntry.validate = function(element, values) { + var idValue = values.processId; + + var bo = getBusinessObject(element); + + var processIdError = utils.isIdValid(bo.processRef, idValue, translate); + + return processIdError ? { processId: processIdError } : {}; + }; + + group.entries.push(idEntry); + + + /** + * process name + */ + var processNameEntry = nameEntryFactory(element, { + id: 'process-name', + label: translate('Process Name') + })[0]; + + // in participants we have to change the default behavior of set and get + processNameEntry.get = function(element) { + return participantHelper.getProcessBusinessObject(element, 'name'); + }; + + processNameEntry.set = function(element, values) { + return participantHelper.modifyProcessBusinessObject(element, 'name', values); + }; + + group.entries.push(processNameEntry); + } + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/CompensateEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/CompensateEventDefinition.js new file mode 100644 index 00000000..3208325c --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/CompensateEventDefinition.js @@ -0,0 +1,130 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'), + eventDefinitionHelper = require('../../../../helper/EventDefinitionHelper'), + utils = require('../../../../Utils'); + +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject, + is = require('bpmn-js/lib/util/ModelUtil').is; + +var forEach = require('lodash/forEach'), + find = require('lodash/find'), + filter = require('lodash/filter'); + + +function getContainedActivities(element) { + return getFlowElements(element, 'bpmn:Activity'); +} + +function getContainedBoundaryEvents(element) { + return getFlowElements(element, 'bpmn:BoundaryEvent'); +} + +function getFlowElements(element, type) { + return utils.filterElementsByType(element.flowElements, type); +} + +function isCompensationEventAttachedToActivity(activity, boundaryEvents) { + var activityId = activity.id; + var boundaryEvent = find(boundaryEvents, function(boundaryEvent) { + var compensateEventDefinition = eventDefinitionHelper.getCompensateEventDefinition(boundaryEvent); + var attachedToRef = boundaryEvent.attachedToRef; + return compensateEventDefinition && attachedToRef && attachedToRef.id === activityId; + }); + return !!boundaryEvent; +} + +// subprocess: only when it is not triggeredByEvent +// activity: only when it attach a compensation boundary event +// callActivity: no limitation +function canActivityBeCompensated(activity, boundaryEvents) { + return (is(activity, 'bpmn:SubProcess') && !activity.triggeredByEvent) || + is(activity, 'bpmn:CallActivity') || + isCompensationEventAttachedToActivity(activity, boundaryEvents); +} + +function getActivitiesForCompensation(element) { + var boundaryEvents = getContainedBoundaryEvents(element); + return filter(getContainedActivities(element), function(activity) { + return canActivityBeCompensated(activity, boundaryEvents); + }); +} + +function getActivitiesForActivityRef(element) { + var bo = getBusinessObject(element); + var parent = bo.$parent; + + var activitiesForActivityRef = getActivitiesForCompensation(parent); + + // if throwing compensation event is in an event sub process: + // get also all activities outside of the event sub process + if (is(parent, 'bpmn:SubProcess') && parent.triggeredByEvent) { + parent = parent.$parent; + if (parent) { + activitiesForActivityRef = activitiesForActivityRef.concat(getActivitiesForCompensation(parent)); + } + + } + + return activitiesForActivityRef; +} + +function createActivityRefOptions(element) { + var options = [ { value: '' } ]; + + var activities = getActivitiesForActivityRef(element); + forEach(activities, function(activity) { + var activityId = activity.id; + var name = (activity.name ? (activity.name + ' ') : '') + '(id=' + activityId + ')'; + options.push({ value: activityId, name: name }); + }); + + return options; +} + + +module.exports = function(group, element, bpmnFactory, compensateEventDefinition, elementRegistry, translate) { + + group.entries.push(entryFactory.checkbox({ + id: 'wait-for-completion', + label: translate('Wait for Completion'), + modelProperty: 'waitForCompletion', + + get: function(element, node) { + return { + waitForCompletion: compensateEventDefinition.waitForCompletion + }; + }, + + set: function(element, values) { + values.waitForCompletion = values.waitForCompletion || false; + return cmdHelper.updateBusinessObject(element, compensateEventDefinition, values); + } + })); + + group.entries.push(entryFactory.selectBox({ + id: 'activity-ref', + label: translate('Activity Ref'), + selectOptions: createActivityRefOptions(element), + modelProperty: 'activityRef', + + get: function(element, node) { + var activityRef = compensateEventDefinition.activityRef; + activityRef = activityRef && activityRef.id; + return { + activityRef: activityRef || '' + }; + }, + + set: function(element, values) { + var activityRef = values.activityRef || undefined; + activityRef = activityRef && getBusinessObject(elementRegistry.get(activityRef)); + return cmdHelper.updateBusinessObject(element, compensateEventDefinition, { + activityRef: activityRef + }); + } + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ConditionalEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ConditionalEventDefinition.js new file mode 100644 index 00000000..dd9b69b8 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ConditionalEventDefinition.js @@ -0,0 +1,54 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var is = require('bpmn-js/lib/util/ModelUtil').is, + isEventSubProcess = require('bpmn-js/lib/util/DiUtil').isEventSubProcess; + +module.exports = function(group, element, bpmnFactory, conditionalEventDefinition, elementRegistry, translate) { + + var getValue = function(modelProperty) { + return function(element) { + var modelPropertyValue = conditionalEventDefinition.get('camunda:' + modelProperty); + var value = {}; + + value[modelProperty] = modelPropertyValue; + return value; + }; + }; + + var setValue = function(modelProperty) { + return function(element, values) { + var props = {}; + + props['camunda:' + modelProperty] = values[modelProperty] || undefined; + + return cmdHelper.updateBusinessObject(element, conditionalEventDefinition, props); + }; + }; + + group.entries.push(entryFactory.textField({ + id: 'variableName', + label: translate('Variable Name'), + modelProperty : 'variableName', + + get: getValue('variableName'), + set: setValue('variableName') + })); + + var isConditionalStartEvent = + is(element, 'bpmn:StartEvent') && !isEventSubProcess(element.parent); + + if (!isConditionalStartEvent) { + group.entries.push(entryFactory.textField({ + id: 'variableEvent', + label: translate('Variable Event'), + description: translate('Specify more than one variable change event as a comma separated list.'), + modelProperty : 'variableEvent', + + get: getValue('variableEvent'), + set: setValue('variableEvent') + })); + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ElementReferenceProperty.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ElementReferenceProperty.js new file mode 100644 index 00000000..c180e574 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ElementReferenceProperty.js @@ -0,0 +1,67 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +var cmdHelper = require('../../../../helper/CmdHelper'); + +/** + * Create an entry to modify a property of an element which + * is referenced by a event definition. + * + * @param {djs.model.Base} element + * @param {ModdleElement} definition + * @param {BpmnFactory} bpmnFactory + * @param {Object} options + * @param {string} options.id the id of the entry + * @param {string} options.label the label of the entry + * @param {string} options.referenceProperty the name of referencing property + * @param {string} options.modelProperty the name of property to modify + * @param {string} options.shouldValidate a flag indicate whether to validate or not + * + * @return {Array} return an array containing the entries + */ +module.exports = function(element, definition, bpmnFactory, options) { + + var id = options.id || 'element-property'; + var label = options.label; + var referenceProperty = options.referenceProperty; + var modelProperty = options.modelProperty || 'name'; + var shouldValidate = options.shouldValidate || false; + + var entry = entryFactory.textField({ + id: id, + label: label, + modelProperty: modelProperty, + + get: function(element, node) { + var reference = definition.get(referenceProperty); + var props = {}; + props[modelProperty] = reference && reference.get(modelProperty); + return props; + }, + + set: function(element, values, node) { + var reference = definition.get(referenceProperty); + var props = {}; + props[modelProperty] = values[modelProperty] || undefined; + return cmdHelper.updateBusinessObject(element, reference, props); + }, + + hidden: function(element, node) { + return !definition.get(referenceProperty); + } + }); + + if (shouldValidate) { + entry.validate = function(element, values, node) { + var reference = definition.get(referenceProperty); + if (reference && !values[modelProperty]) { + var validationErrors = {}; + validationErrors[modelProperty] = 'Must provide a value'; + return validationErrors; + } + }; + } + + return [ entry ]; +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ErrorEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ErrorEventDefinition.js new file mode 100644 index 00000000..5edd9f3d --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/ErrorEventDefinition.js @@ -0,0 +1,35 @@ +'use strict'; + +var eventDefinitionReference = require('./EventDefinitionReference'), + elementReferenceProperty = require('./ElementReferenceProperty'); + + +module.exports = function(group, element, bpmnFactory, errorEventDefinition, translate) { + + + group.entries = group.entries.concat(eventDefinitionReference(element, errorEventDefinition, bpmnFactory, { + label: translate('Error'), + elementName: 'error', + elementType: 'bpmn:Error', + referenceProperty: 'errorRef', + newElementIdPrefix: 'Error_' + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, errorEventDefinition, bpmnFactory, { + id: 'error-element-name', + label: translate('Error Name'), + referenceProperty: 'errorRef', + modelProperty: 'name', + shouldValidate: true + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, errorEventDefinition, bpmnFactory, { + id: 'error-element-code', + label: translate('Error Code'), + referenceProperty: 'errorRef', + modelProperty: 'errorCode' + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EscalationEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EscalationEventDefinition.js new file mode 100644 index 00000000..a8018c8a --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EscalationEventDefinition.js @@ -0,0 +1,58 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var eventDefinitionReference = require('./EventDefinitionReference'), + elementReferenceProperty = require('./ElementReferenceProperty'); + + +module.exports = function(group, element, bpmnFactory, escalationEventDefinition, showEscalationCodeVariable, translate) { + + group.entries = group.entries.concat(eventDefinitionReference(element, escalationEventDefinition, bpmnFactory, { + label: translate('Escalation'), + elementName: 'escalation', + elementType: 'bpmn:Escalation', + referenceProperty: 'escalationRef', + newElementIdPrefix: 'Escalation_' + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, escalationEventDefinition, bpmnFactory, { + id: 'escalation-element-name', + label: translate('Escalation Name'), + referenceProperty: 'escalationRef', + modelProperty: 'name', + shouldValidate: true + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, escalationEventDefinition, bpmnFactory, { + id: 'escalation-element-code', + label: translate('Escalation Code'), + referenceProperty: 'escalationRef', + modelProperty: 'escalationCode' + })); + + + if (showEscalationCodeVariable) { + group.entries.push(entryFactory.textField({ + id : 'escalationCodeVariable', + label : translate('Escalation Code Variable'), + modelProperty : 'escalationCodeVariable', + + get: function(element) { + var codeVariable = escalationEventDefinition.get('camunda:escalationCodeVariable'); + return { + escalationCodeVariable: codeVariable + }; + }, + + set: function(element, values) { + return cmdHelper.updateBusinessObject(element, escalationEventDefinition, { + 'camunda:escalationCodeVariable': values.escalationCodeVariable || undefined + }); + } + })); + } +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EventDefinitionReference.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EventDefinitionReference.js new file mode 100644 index 00000000..71bab1b6 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/EventDefinitionReference.js @@ -0,0 +1,150 @@ +'use strict'; + +var cmdHelper = require('../../../../helper/CmdHelper'); + +var domQuery = require('min-dom').query, + domify = require('min-dom').domify, + domAttr = require('min-dom').attr; + +var forEach = require('lodash/forEach'), + find = require('lodash/find'); + +var elementHelper = require('../../../../helper/ElementHelper'); +var utils = require('../../../../Utils'), + escapeHTML = utils.escapeHTML; + +var selector = 'select[name=selectedElement]'; + +/** + * Get select box containing all elements. + * + * @param {DOMElement} node + * + * @return {DOMElement} the select box + */ +function getSelectBox(node) { + return domQuery(selector, node.parentElement); +} + +/** + * Find element by given id. + * + * @param {ModdleElement} eventDefinition + * + * @return {ModdleElement} an element + */ +function findElementById(eventDefinition, type, id) { + var elements = utils.findRootElementsByType(eventDefinition, type); + return find(elements, function(element) { + return element.id === id; + }); +} + +/** + * Create an entry to modify the reference to an element from an + * event definition. + * + * @param {djs.model.Base} element + * @param {ModdleElement} definition + * @param {BpmnFactory} bpmnFactory + * @param {Object} options + * @param {string} options.label the label of the entry + * @param {string} options.description the description of the entry + * @param {string} options.elementName the name of the element + * @param {string} options.elementType the type of the element + * @param {string} options.referenceProperty the name of referencing property + * @param {string} options.newElementIdPrefix the prefix of a new created element + * + * @return {Array} return an array containing the entries + */ +module.exports = function(element, definition, bpmnFactory, options) { + + var elementName = options.elementName || '', + elementType = options.elementType, + referenceProperty = options.referenceProperty; + + var newElementIdPrefix = options.newElementIdPrefix || 'elem_'; + + var label = options.label || '', + description = options.description || ''; + + var entries = []; + + entries.push({ + + id: 'event-definitions-' + elementName, + description: description, + html: '' + + '' + escapeHTML(label) + '' + + '' + + '' + + '' + + '+' + + '' + + '', + + get: function(element, entryNode) { + utils.updateOptionsDropDown(selector, definition, elementType, entryNode); + var reference = definition.get(referenceProperty); + return { + selectedElement: (reference && reference.id) || '' + }; + }, + + set: function(element, values) { + var selection = values.selectedElement; + + var props = {}; + + if (!selection || typeof selection === 'undefined') { + // remove reference to element + props[referenceProperty] = undefined; + return cmdHelper.updateBusinessObject(element, definition, props); + } + + var commands = []; + + var selectedElement = findElementById(definition, elementType, selection); + if (!selectedElement) { + var root = utils.getRoot(definition); + + // create a new element + selectedElement = elementHelper.createElement(elementType, { name: selection }, root, bpmnFactory); + commands.push(cmdHelper.addAndRemoveElementsFromList(element, root, 'rootElements', null, [ selectedElement ])); + } + + // update reference to element + props[referenceProperty] = selectedElement; + commands.push(cmdHelper.updateBusinessObject(element, definition, props)); + + return commands; + }, + + addElement: function(element, inputNode) { + // note: this generated id will be used as name + // of the element and not as id + var id = utils.nextId(newElementIdPrefix); + + var optionTemplate = domify(' (id='+escapeHTML(id)+')' + ''); + + // add new option + var selectBox = getSelectBox(inputNode); + selectBox.insertBefore(optionTemplate, selectBox.firstChild); + + // select new element in the select box + forEach(selectBox, function(option) { + if (option.value === id) { + domAttr(option, 'selected', 'selected'); + } else { + domAttr(option, 'selected', null); + } + }); + + return true; + } + + }); + + return entries; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/MessageEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/MessageEventDefinition.js new file mode 100644 index 00000000..0bd03dcd --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/MessageEventDefinition.js @@ -0,0 +1,26 @@ +'use strict'; + +var eventDefinitionReference = require('./EventDefinitionReference'), + elementReferenceProperty = require('./ElementReferenceProperty'); + + +module.exports = function(group, element, bpmnFactory, messageEventDefinition, translate) { + + group.entries = group.entries.concat(eventDefinitionReference(element, messageEventDefinition, bpmnFactory, { + label: translate('Message'), + elementName: 'message', + elementType: 'bpmn:Message', + referenceProperty: 'messageRef', + newElementIdPrefix: 'Message_' + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, messageEventDefinition, bpmnFactory, { + id: 'message-element-name', + label: translate('Message Name'), + referenceProperty: 'messageRef', + modelProperty: 'name', + shouldValidate: true + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/Name.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/Name.js new file mode 100644 index 00000000..1e5f5353 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/Name.js @@ -0,0 +1,33 @@ +'use strict'; + +var entryFactory = require('../../../../factory/EntryFactory'); + +/** + * Create an entry to modify the name of an an element. + * + * @param {djs.model.Base} element + * @param {Object} options + * @param {string} options.id the id of the entry + * @param {string} options.label the label of the entry + * + * @return {Array} return an array containing + * the entry to modify the name + */ +module.exports = function(element, options, translate) { + + options = options || {}; + var id = options.id || 'name', + label = options.label || translate('Name'), + modelProperty = options.modelProperty || 'name'; + + var nameEntry = entryFactory.textBox({ + id: id, + label: label, + modelProperty: modelProperty, + get: options.get, + set: options.set + }); + + return [ nameEntry ]; + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/SignalEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/SignalEventDefinition.js new file mode 100644 index 00000000..85098ed6 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/SignalEventDefinition.js @@ -0,0 +1,26 @@ +'use strict'; + +var eventDefinitionReference = require('./EventDefinitionReference'), + elementReferenceProperty = require('./ElementReferenceProperty'); + + +module.exports = function(group, element, bpmnFactory, signalEventDefinition, translate) { + + group.entries = group.entries.concat(eventDefinitionReference(element, signalEventDefinition, bpmnFactory, { + label: translate('Signal'), + elementName: 'signal', + elementType: 'bpmn:Signal', + referenceProperty: 'signalRef', + newElementIdPrefix: 'Signal_' + })); + + + group.entries = group.entries.concat(elementReferenceProperty(element, signalEventDefinition, bpmnFactory, { + id: 'signal-element-name', + label: translate('Signal Name'), + referenceProperty: 'signalRef', + modelProperty: 'name', + shouldValidate: true + })); + +}; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/TimerEventDefinition.js b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/TimerEventDefinition.js new file mode 100644 index 00000000..f8a812e8 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/properties-panel/provider/bpmn/parts/implementation/TimerEventDefinition.js @@ -0,0 +1,139 @@ +'use strict'; + +var elementHelper = require('../../../../helper/ElementHelper'), + cmdHelper = require('../../../../helper/CmdHelper'); + +var entryFactory = require('../../../../factory/EntryFactory'); + +/** + * Get the timer definition type for a given timer event definition. + * + * @param {ModdleElement} timer + * + * @return {string|undefined} the timer definition type + */ +function getTimerDefinitionType(timer) { + var timeDate = timer.get('timeDate'); + if (typeof timeDate !== 'undefined') { + return 'timeDate'; + } + + var timeCycle = timer.get('timeCycle'); + if (typeof timeCycle !== 'undefined') { + return 'timeCycle'; + } + + var timeDuration = timer.get('timeDuration'); + if (typeof timeDuration !== 'undefined') { + return 'timeDuration'; + } +} + +/** + * Creates 'bpmn:FormalExpression' element. + * + * @param {ModdleElement} parent + * @param {string} body + * @param {BpmnFactory} bpmnFactory + * + * @return {ModdleElement} a formal expression + */ +function createFormalExpression(parent, body, bpmnFactory) { + body = body || undefined; + return elementHelper.createElement('bpmn:FormalExpression', { body: body }, parent, bpmnFactory); +} + +function TimerEventDefinition(group, element, bpmnFactory, timerEventDefinition, translate) { + + var selectOptions = [ + { value: 'timeDate', name: translate('Date') }, + { value: 'timeDuration', name: translate('Duration') }, + { value: 'timeCycle', name: translate('Cycle') } + ]; + + group.entries.push(entryFactory.selectBox({ + id: 'timer-event-definition-type', + label: translate('Timer Definition Type'), + selectOptions: selectOptions, + emptyParameter: true, + modelProperty: 'timerDefinitionType', + + get: function(element, node) { + return { + timerDefinitionType: getTimerDefinitionType(timerEventDefinition) || '' + }; + }, + + set: function(element, values) { + var props = { + timeDuration: undefined, + timeDate: undefined, + timeCycle: undefined + }; + + var newType = values.timerDefinitionType; + if (values.timerDefinitionType) { + var oldType = getTimerDefinitionType(timerEventDefinition); + + var value; + if (oldType) { + var definition = timerEventDefinition.get(oldType); + value = definition.get('body'); + } + + props[newType] = createFormalExpression(timerEventDefinition, value, bpmnFactory); + } + + return cmdHelper.updateBusinessObject(element, timerEventDefinition, props); + } + + })); + + + group.entries.push(entryFactory.textField({ + id: 'timer-event-definition', + label: translate('Timer Definition'), + modelProperty: 'timerDefinition', + + get: function(element, node) { + var type = getTimerDefinitionType(timerEventDefinition); + var definition = type && timerEventDefinition.get(type); + var value = definition && definition.get('body'); + return { + timerDefinition: value + }; + }, + + set: function(element, values) { + var type = getTimerDefinitionType(timerEventDefinition); + var definition = type && timerEventDefinition.get(type); + + if (definition) { + return cmdHelper.updateBusinessObject(element, definition, { + body: values.timerDefinition || undefined + }); + } + }, + + validate: function(element) { + var type = getTimerDefinitionType(timerEventDefinition); + var definition = type && timerEventDefinition.get(type); + if (definition) { + var value = definition.get('body'); + if (!value) { + return { + timerDefinition: translate('Must provide a value') + }; + } + } + }, + + hidden: function(element) { + return !getTimerDefinitionType(timerEventDefinition); + } + + })); + +} + +module.exports = TimerEventDefinition; diff --git a/ruoyi-ui/xjs-bpmnjs/resources/tools.js b/ruoyi-ui/xjs-bpmnjs/resources/tools.js new file mode 100644 index 00000000..a61a3ebe --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/resources/tools.js @@ -0,0 +1,273 @@ +/** + * @description 全局功能封装 + * @author zr + * @type {{registerFileDrop(*, *): void, saveBpmn(Object): void, handleDragOver(*): void, setColor(Object): void, downLoad(Object): void, upload(Object, Object, Object): void, handleFileSelect(*): void, setEncoded(Object, string, string): void, openFromUrl(Object, Object, Object, string): void, createDiagram(string, Object, Object): Promise, getUrlParam: tools.getUrlParam}} + */ + +import $ from 'jquery'; +const proHost = window.location.protocol + "//" + window.location.host; +const href = window.location.href.split("bpmnjs")[0]; +const key = href.split(window.location.host)[1]; +const publicurl = proHost + key; +const tools = { + registerFileDrop(container, callback) { + container.get(0).addEventListener('dragover', tools.handleDragOver, false); + container.get(0).addEventListener('drop', tools.handleFileSelect, false); + }, + /** + * 获取地址栏参数 + * @param {string} value + */ + getUrlParam: function (url) { + var object = {}; + if (url.indexOf("?") != -1) { + var str = url.split("?")[1]; + var strs = str.split("&"); + for (var i = 0; i < strs.length; i++) { + object[strs[i].split("=")[0]] = strs[i].split("=")[1] + } + return object + } + return object[url]; + }, + /** + * 通过xml创建bpmn + * @param {string} xml 创建bpms xml + * @param {object} bpmnModeler bpmn对象 + * @param {object} container 容器对象 + */ + async createDiagram(xml, bpmnModeler, container) { + try { + await bpmnModeler.importXML(xml); + container.removeClass('with-error').addClass('with-diagram'); + } catch (err) { + container.removeClass('with-diagram').addClass('with-error'); + container.find('.error pre').text(err.message); + console.error(err); + } + }, + /** + * 通过Json设置颜色 + * @param {object} json json 字符串 + */ + setColor(json,bpmnModeler) { + var modeling = bpmnModeler.get('modeling'); + var elementRegistry = bpmnModeler.get('elementRegistry') + var elementToColor = elementRegistry.get(json.name); + if(elementToColor){ + modeling.setColor([elementToColor], { + stroke: json.stroke, + fill: json.fill + }); + } + }, + /** + * 保存bpmn对象 + * @param {object} bpmnModeler bpmn对象 + */ + saveBpmn(bpmnModeler) { + bpmnModeler.saveXML({ format: true }, function (err, xml) { + if (err) { + return console.error('保存失败,请重试', err); + } + console.log(xml) + var param={ + "stringBPMN":xml + } + $.ajax({ + url: localStorage.getItem("VUE_APP_BASE_API")+'/processDefinition/addDeploymentByString', + type: 'POST', + dataType:"json", + data: param, + //headers:{'Content-Type':'application/json;charset=utf8'}, + success: function (result) { + if(result.code===200){ + tools.syhide('alert') + }else{ + alert(result.msg) + } + }, + error: function (err) { + console.log(err) + } + }); + }); + }, + /** + * 下载bpmn + * @param {object} bpmnModeler bpmn对象 + */ + downLoad(bpmnModeler) { + var downloadLink = $("#downloadBpmn") + bpmnModeler.saveXML({ format: true }, function (err, xml) { + if (err) { + return console.error('could not save BPMN 2.0 diagram', err); + } + tools.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml); + }); + }, + /** + * 转码xml并下载 + * @param {object} link 按钮 + * @param {string} name 下载名称 + * @param {string} data base64XML + */ + setEncoded(link, name, data) { + var encodedData = encodeURIComponent(data); + if (data) { + link.addClass('active').attr({ + 'href': 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData, + 'download': name + }); + } else { + link.removeClass('active'); + } + }, + /** + * 上传bpmn + * @param {object} bpmnModeler bpmn对象 + * @param {object} container 容器对象 + */ + upload(bpmnModeler, container) { + var FileUpload = document.myForm.uploadFile.files[0]; + var fm = new FormData(); + fm.append('processFile', FileUpload); + $.ajax({ + url: localStorage.getItem("VUE_APP_BASE_API")+'/processDefinition/upload', + // url: 'http://localhost:8080/processDefinition/upload', + type: 'POST', + data: fm, + async: false, + contentType: false, //禁止设置请求类型 + processData: false, //禁止jquery对DAta数据的处理,默认会处理 + success: function (result) { + var url = result.data.substr(0,4)=="http"?result.data:localStorage.getItem("VUE_APP_BASE_API")+ result.data + tools.openFromUrl(bpmnModeler, container, url) + }, + error: function (err) { + console.log(err) + } + }); + }, + /** + * 打开xml Url 地址 + * @param {object} bpmnModeler bpmn对象 + * @param {object} container 容器对象 + * @param {string} url url地址 + */ + openFromUrl(bpmnModeler, container, url) { + $.ajax(url, { dataType: 'text' }).done(async function (xml) { + try { + await bpmnModeler.importXML(xml); + container.removeClass('with-error').addClass('with-diagram'); + } catch (err) { + console.error(err); + } + }); + }, + /** + * 打开弹出框 + * @param id + */ + syopen(id) { + var dom = $("#" + id); + this.sycenter(dom); + dom.addClass(name); + dom.show(); + var that = this; + $(".sy-mask").fadeIn(300) + setTimeout(function() { + dom.removeClass(name) + }, 300); + + }, + /** + * 隐藏弹出框 + * @param id + */ + syhide(id) { + if (typeof id == "undefined") { + var dom = $(".sy-alert") + } else { + var dom = $("#" + id) + } + var name = dom.attr("sy-leave"); + dom.addClass(name); + $(".sy-mask").fadeOut(300); + setTimeout(function() { + dom.hide(); + dom.removeClass(name); + }, 300) + }, + /** + * 弹出框居中 + * @param dom + */ + sycenter(dom) { + var mgtop = parseFloat(dom.height() / 2); + dom.css({ + "top": "50%", + "margin-top": "-" + mgtop + "px" + }) + }, + /** + * 判断是否是数组 + * @param value + * @returns {arg is Array|boolean} + */ + isArrayFn(value){ + if (typeof Array.isArray === "function") { + return Array.isArray(value); + }else{ + return Object.prototype.toString.call(value) === "[object Array]"; + } + }, + /** + * 根据数据设置颜色 + * @param data + * @returns {Array} + */ + getByColor(data){ + + var ColorJson=[] + for(var k in data['highLine']){ + var par={ + "name": data['highLine'][k], + "stroke":"green", + "fill":"green" + } + ColorJson.push(par) + } + for(var k in data['highPoint']){ + var par={ + "name": data['highPoint'][k], + "stroke":"gray", + "fill":"#eae9e9" + + } + ColorJson.push(par) + } + for(var k in data['iDo']){ + var par={ + "name": data['iDo'][k], + "stroke":"green", + "fill":"#a3d68e" + } + ColorJson.push(par) + } + for(var k in data['waitingToDo']){ + var par={ + "name": data['waitingToDo'][k], + "stroke":"green", + "fill":"yellow" + } + ColorJson.push(par) + } + return ColorJson + } +} + + + + +export default tools diff --git a/ruoyi-ui/xjs-bpmnjs/styles/app.less b/ruoyi-ui/xjs-bpmnjs/styles/app.less new file mode 100644 index 00000000..7c5a5755 --- /dev/null +++ b/ruoyi-ui/xjs-bpmnjs/styles/app.less @@ -0,0 +1,135 @@ +@import "bpmn-js-properties-panel/styles/properties"; + +* { + box-sizing: border-box; +} + +body, +html { + + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + + font-size: 12px; + + height: 100%; + max-height: 100%; + padding: 0; + margin: 0; +} + +a:link { + text-decoration: none; +} + +.content { + position: relative; + width: 100%; + height: 100%; + + > .message { + width: 100%; + height: 100%; + text-align: center; + display: table; + + font-size: 16px; + color: #111; + + .note { + vertical-align: middle; + text-align: center; + display: table-cell; + } + + &.error { + .details { + max-width: 500px; + font-size: 12px; + margin: 20px auto; + text-align: left; + color: #BD2828; + } + + pre { + border: solid 1px #BD2828; + background: #fefafa; + padding: 10px; + color: #BD2828; + } + } + } + &:not(.with-error) .error, + &.with-error .intro, + &.with-diagram .intro { + display: none; + } + + .canvas { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + + .canvas, + .properties-panel-parent { + display: none; + } + + &.with-diagram { + .canvas, + .properties-panel-parent { + display: block; + } + } +} + + +.buttons { + position: fixed; + bottom: 20px; + left: 20px; + + padding: 0; + margin: 0; + list-style: none; + + > li { + display: inline-block; + margin-right: 10px; + + > a { + background: #DDD; + border: solid 1px #666; + display: inline-block; + padding: 5px; + } + } + + a { + opacity: 0.3; + } + + a.active { + opacity: 1.0; + } +} + +.properties-panel-parent { + position: absolute; + top: 0; + bottom: 0; + right: 0; + width: 260px; + z-index: 10; + border-left: 1px solid #ccc; + overflow: auto; + &:empty { + display: none; + } + > .djs-properties-panel { + padding-bottom: 70px; + min-height:100%; + } +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/XjsWorkflowApp.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/XjsWorkflowApp.java index 71eea155..d446c26d 100644 --- a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/XjsWorkflowApp.java +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/XjsWorkflowApp.java @@ -4,17 +4,20 @@ import com.ruoyi.common.security.annotation.EnableCustomConfig; import com.ruoyi.common.security.annotation.EnableRyFeignClients; import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; /** * 工作流服务启动器 * @author xiejs * @since 2022-04-16 */ -@SpringBootApplication @EnableCustomConfig @EnableCustomSwagger2 @EnableRyFeignClients +//排除security自动配置:解决activiti自带springSecurity依赖自动配置导致跨域问题 +@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class}) public class XjsWorkflowApp { public static void main(String[] args) { SpringApplication.run(XjsWorkflowApp.class, args); diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ActivitiHistoryController.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ActivitiHistoryController.java index 37a0a2c8..4d6d15a1 100644 --- a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ActivitiHistoryController.java +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ActivitiHistoryController.java @@ -5,6 +5,7 @@ import com.ruoyi.common.core.web.domain.AjaxResult; import com.xjs.activiti.domain.dto.ActivitiHighLineDTO; import com.xjs.activiti.service.IActivitiHistoryService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -22,6 +23,7 @@ public class ActivitiHistoryController { //流程图高亮 @GetMapping("/gethighLine") + @ApiOperation("流程图高亮") public AjaxResult gethighLine(@RequestParam("instanceId") String instanceId) { ActivitiHighLineDTO activitiHighLineDTO = activitiHistoryService.gethighLine(instanceId); diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/HistoryFormDataCoroller.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/HistoryFormDataCoroller.java index 734638eb..6971da4b 100644 --- a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/HistoryFormDataCoroller.java +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/HistoryFormDataCoroller.java @@ -3,6 +3,7 @@ package com.xjs.activiti.controller; import com.ruoyi.common.core.web.domain.AjaxResult; import com.xjs.activiti.service.IFormHistoryDataService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -17,6 +18,7 @@ public class HistoryFormDataCoroller { private IFormHistoryDataService formHistoryDataService; @GetMapping(value = "/ByInstanceId/{instanceId}") + @ApiOperation("历史表格数据") public AjaxResult historyFromData(@PathVariable("instanceId") String instanceId) { return AjaxResult.success(formHistoryDataService.historyDataShow(instanceId)); diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ProcessDefinitionController.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ProcessDefinitionController.java index 6ce92f0c..8481f41c 100644 --- a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ProcessDefinitionController.java +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/controller/ProcessDefinitionController.java @@ -11,6 +11,7 @@ import com.ruoyi.common.log.enums.BusinessType; import com.xjs.activiti.domain.dto.ProcessDefinitionDTO; import com.xjs.activiti.service.IProcessDefinitionService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -18,9 +19,8 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; - @RestController -@RequestMapping("/processDefinition") +@RequestMapping("processDefinition") @Api(tags = "工作流-流程定义") public class ProcessDefinitionController extends BaseController { @@ -35,16 +35,16 @@ public class ProcessDefinitionController extends BaseController { * @return */ @GetMapping(value = "/list") + @ApiOperation("获取流程定义集合") public TableDataInfo list(ProcessDefinitionDTO processDefinition) { PageDomain pageDomain = TableSupport.buildPageRequest(); return getDataTable(processDefinitionService.selectProcessDefinitionList(processDefinition, pageDomain)); } - /** - * @return - */ + @GetMapping(value = "/getDefinitions/{instanceId}") + @ApiOperation("按实例 ID 获取定义") public AjaxResult getDefinitionsByInstanceId(@PathVariable("instanceId") String instanceId) { return AjaxResult.success(processDefinitionService.getDefinitionsByInstanceId(instanceId)); } @@ -57,6 +57,7 @@ public class ProcessDefinitionController extends BaseController { */ @Log(title = "流程定义管理", businessType = BusinessType.DELETE) @DeleteMapping(value = "/remove/{deploymentId}") + @ApiOperation("删除流程定义") public AjaxResult delDefinition(@PathVariable("deploymentId") String deploymentId) { return toAjax(processDefinitionService.deleteProcessDefinitionById(deploymentId)); } @@ -70,6 +71,7 @@ public class ProcessDefinitionController extends BaseController { */ @Log(title = "流程定义管理", businessType = BusinessType.IMPORT) @PostMapping(value = "/uploadStreamAndDeployment") + @ApiOperation("上传并部署流程定义") public AjaxResult uploadStreamAndDeployment(@RequestParam("file") MultipartFile file) throws IOException { processDefinitionService.uploadStreamAndDeployment(file); return AjaxResult.success(); @@ -84,7 +86,7 @@ public class ProcessDefinitionController extends BaseController { */ @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) @PostMapping("/suspendOrActiveApply") - @ResponseBody + @ApiOperation("启动挂起流程流程定义") public AjaxResult suspendOrActiveApply(@RequestBody ProcessDefinitionDTO processDefinition) { processDefinitionService.suspendOrActiveApply(processDefinition.getId(), processDefinition.getSuspendState()); return AjaxResult.success(); @@ -99,6 +101,7 @@ public class ProcessDefinitionController extends BaseController { */ @Log(title = "流程定义管理", businessType = BusinessType.IMPORT) @PostMapping(value = "/upload") + @ApiOperation("上传流程流程定义") public AjaxResult upload(@RequestParam("processFile") MultipartFile multipartFile) throws IOException { if (!multipartFile.isEmpty()) { @@ -117,6 +120,7 @@ public class ProcessDefinitionController extends BaseController { * @return */ @PostMapping(value = "/addDeploymentByString") + @ApiOperation("通过stringBPMN添加流程定义") public AjaxResult addDeploymentByString(@RequestParam("stringBPMN") String stringBPMN) { processDefinitionService.addDeploymentByString(stringBPMN); return AjaxResult.success(); diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/service/impl/ProcessDefinitionServiceImpl.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/service/impl/ProcessDefinitionServiceImpl.java index 26437a03..be85c6bc 100644 --- a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/service/impl/ProcessDefinitionServiceImpl.java +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/activiti/service/impl/ProcessDefinitionServiceImpl.java @@ -32,6 +32,7 @@ import java.util.zip.ZipInputStream; /** * 流程定义服务接口实现 + * * @author xiejs * @since 2022-04-17 01:50:42 */ @@ -60,8 +61,8 @@ public class ProcessDefinitionServiceImpl implements IProcessDefinitionService { List processDefinitions = processDefinitionQuery.listPage((pageDomain.getPageNum() - 1) * pageDomain.getPageSize(), pageDomain.getPageSize()); long count = processDefinitionQuery.count(); list.setTotal(count); - if (count!=0) { - Set ids = processDefinitions.parallelStream().map(pdl -> pdl.getDeploymentId()).collect(Collectors.toSet()); + if (count != 0) { + Set ids = processDefinitions.parallelStream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toSet()); List actReDeploymentVOS = actReDeploymentMapper.selectActReDeploymentByIds(ids); List processDefinitionDTOS = processDefinitions.stream() .map(pd -> new ProcessDefinitionDTO((ProcessDefinitionEntityImpl) pd, actReDeploymentVOS.parallelStream().filter(ard -> pd.getDeploymentId().equals(ard.getId())).findAny().orElse(new ActReDeploymentVO()))) @@ -94,7 +95,7 @@ public class ProcessDefinitionServiceImpl implements IProcessDefinitionService { // 文件的扩展名 String extension = FilenameUtils.getExtension(fileName); - if (extension.equals("zip")) { + if ("zip".equals(extension)) { ZipInputStream zip = new ZipInputStream(fileInputStream); repositoryService.createDeployment()//初始化流程 .addZipInputStream(zip) @@ -109,19 +110,19 @@ public class ProcessDefinitionServiceImpl implements IProcessDefinitionService { @Override public void suspendOrActiveApply(String id, Integer suspendState) { - if (1==suspendState) { + if (1 == suspendState) { // 当流程定义被挂起时,已经发起的该流程定义的流程实例不受影响(如果选择级联挂起则流程实例也会被挂起)。 // 当流程定义被挂起时,无法发起新的该流程定义的流程实例。 // 直观变化:act_re_procdef 的 SUSPENSION_STATE_ 为 2 repositoryService.suspendProcessDefinitionById(id); - } else if (2==suspendState) { + } else if (2 == suspendState) { repositoryService.activateProcessDefinitionById(id); } } @Override public String upload(MultipartFile multipartFile) throws IOException { - //return FileUploadUtils.upload(RuoYiConfig.getUploadPath()+"/processDefinition" , multipartFile); + //return FileUploadUtils.upload(RuoYiConfig.getUploadPath()+"/processDefinition" , multipartFile); return ""; } diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/controller/WorkflowLeaveController.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/controller/WorkflowLeaveController.java new file mode 100644 index 00000000..ddccf1a4 --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/controller/WorkflowLeaveController.java @@ -0,0 +1,125 @@ +package com.xjs.workflow.leave.controller; + + +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.xjs.workflow.leave.domain.WorkflowLeave; +import com.xjs.workflow.leave.service.IWorkflowLeaveService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 请假Controller + * + * @author xiejs + * @since 2022-04-17 17:54:05 + */ +@RestController +@RequestMapping("/workflow/leave") +@Api(tags = "工作流-请假流程") +public class WorkflowLeaveController extends BaseController { + @Autowired + private IWorkflowLeaveService workflowLeaveService; + + /** + * 查询请假列表 + */ + @GetMapping("/list") + @RequiresPermissions("workflow:leave:list") + @ApiOperation("查询请假列表") + public TableDataInfo list(WorkflowLeave workflowLeave) { + startPage(); + workflowLeave.setCreateBy(SecurityUtils.getUsername()); + List list = workflowLeaveService.selectWorkflowLeaveAndTaskNameList(workflowLeave); + return getDataTable(list); + } + + /** + * 查询请假列表 + */ + @GetMapping("/listAll") + @RequiresPermissions("workflow:leave:list") + @ApiOperation("查询请假列表") + public TableDataInfo listAll(WorkflowLeave workflowLeave) { + startPage(); + List list = workflowLeaveService.selectWorkflowLeaveList(workflowLeave); + return getDataTable(list); + } + + /** + * 导出请假列表 + */ + @Log(title = "请假", businessType = BusinessType.EXPORT) + @GetMapping("/export") + @RequiresPermissions("workflow:leave:export") + @ApiOperation("导出请假列表") + public void export(HttpServletResponse response, WorkflowLeave workflowLeave) { + List list = workflowLeaveService.selectWorkflowLeaveList(workflowLeave); + ExcelUtil util = new ExcelUtil<>(WorkflowLeave.class); + util.exportExcel(response, list, "leave"); + } + + /** + * 获取请假详细信息 + */ + @GetMapping(value = "/{id}") + @RequiresPermissions("workflow:leave:query") + @ApiOperation("获取请假详细信息id") + public AjaxResult getInfo(@PathVariable("id") String id) { + return AjaxResult.success(workflowLeaveService.selectWorkflowLeaveById(id)); + } + + /** + * 获取请假详细信息 + */ + @GetMapping(value = "ByInstanceId/{instanceId}") + @RequiresPermissions("workflow:leave:query") + @ApiOperation("获取请假详细信息InstanceId") + public AjaxResult getInfoByInstanceId(@PathVariable("instanceId") String instanceId) { + return AjaxResult.success(workflowLeaveService.selectWorkflowLeaveByInstanceId(instanceId)); + } + + /** + * 新增请假 + */ + @RequiresPermissions("workflow:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @PostMapping + @ApiOperation("新增请假") + public AjaxResult add(@RequestBody WorkflowLeave workflowLeave) { + return toAjax(workflowLeaveService.insertWorkflowLeave(workflowLeave)); + } + + /** + * 修改请假 + */ + @Log(title = "请假", businessType = BusinessType.UPDATE) + @ApiOperation("修改请假") + @PutMapping + @RequiresPermissions("workflow:leave:edit") + public AjaxResult edit(@RequestBody WorkflowLeave workflowLeave) { + return toAjax(workflowLeaveService.insertWorkflowLeave(workflowLeave)); + } + + /** + * 删除请假 + */ + @RequiresPermissions("workflow:leave:remove") + @Log(title = "请假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @ApiOperation("删除请假") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(workflowLeaveService.deleteWorkflowLeaveByIds(ids)); + } +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/domain/WorkflowLeave.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/domain/WorkflowLeave.java new file mode 100644 index 00000000..6d8b48e1 --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/domain/WorkflowLeave.java @@ -0,0 +1,169 @@ +package com.xjs.workflow.leave.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.web.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.Date; + +/** + * 请假对象 workflow_leave + * + * @author xiejs + * @since 2022-04-17 17:53:55 + */ +public class WorkflowLeave extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + private String id; + + /** + * 请假类型 + */ + @Excel(name = "请假类型") + private String type; + + /** + * 标题 + */ + @Excel(name = "标题") + private String title; + + /** + * 原因 + */ + @Excel(name = "原因") + private String reason; + + /** + * 开始时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date leaveStartTime; + + /** + * 结束时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date leaveEndTime; + + + private String instanceId; + private String taskName; + + /** + * 状态 + */ + @Excel(name = "状态") + private String state; + + /** + * 创建人 + */ + @Excel(name = "创建人") + private String createName; + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getReason() { + return reason; + } + + public void setLeaveStartTime(Date leaveStartTime) { + this.leaveStartTime = leaveStartTime; + } + + public Date getLeaveStartTime() { + return leaveStartTime; + } + + public void setLeaveEndTime(Date leaveEndTime) { + this.leaveEndTime = leaveEndTime; + } + + public Date getLeaveEndTime() { + return leaveEndTime; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setState(String state) { + this.state = state; + } + + public String getState() { + return state; + } + + public String getCreateName() { + return createName; + } + + public void setCreateName(String createName) { + this.createName = createName; + } + + public String getTaskName() { + return taskName; + } + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("type", getType()) + .append("title", getTitle()) + .append("reason", getReason()) + .append("leaveStartTime", getLeaveStartTime()) + .append("leaveEndTime", getLeaveEndTime()) + .append("instanceId", getInstanceId()) + .append("state", getState()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/instener/LeaveEndStateListener.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/instener/LeaveEndStateListener.java new file mode 100644 index 00000000..1e425262 --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/instener/LeaveEndStateListener.java @@ -0,0 +1,25 @@ +package com.xjs.workflow.leave.instener; + +import com.ruoyi.common.core.utils.SpringUtils; +import com.xjs.workflow.leave.domain.WorkflowLeave; +import com.xjs.workflow.leave.service.IWorkflowLeaveService; +import org.activiti.engine.delegate.DelegateExecution; +import org.activiti.engine.delegate.ExecutionListener; +import org.activiti.engine.delegate.Expression; + +/** + * act监听器 + * @author xiejs + * @since 2022-04-17 17:54:27 + */ +public class LeaveEndStateListener implements ExecutionListener { + private Expression state; + + @Override + public void notify(DelegateExecution delegateExecution) { + WorkflowLeave workflowLeave = new WorkflowLeave(); + workflowLeave.setId(delegateExecution.getProcessInstanceBusinessKey()); + workflowLeave.setState(state.getValue(delegateExecution).toString()); + SpringUtils.getBean(IWorkflowLeaveService.class).updateWorkflowLeave(workflowLeave); + } +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/mapper/WorkflowLeaveMapper.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/mapper/WorkflowLeaveMapper.java new file mode 100644 index 00000000..a8452bb9 --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/mapper/WorkflowLeaveMapper.java @@ -0,0 +1,79 @@ +package com.xjs.workflow.leave.mapper; + +import com.xjs.workflow.leave.domain.WorkflowLeave; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 请假Mapper接口 + * + * @author xiejs + * @since 2022-04-17 17:54:39 + */ +public interface WorkflowLeaveMapper { + /** + * 查询请假 + * + * @param id 请假ID + * @return 请假 + */ + WorkflowLeave selectWorkflowLeaveById(String id); + + /** + * 查询请假 + * + * @param instanceId 请假ID + * @return 请假 + */ + WorkflowLeave selectWorkflowLeaveByInstanceId(String instanceId); + + /** + * 查询请假列表根据部门编号和WorkflowLeave + * + * @param workflowLeave 请假 + * @return 请假集合 + */ + List selectWorkflowLeaveListByWorkflowLeaveAndDeptId(@Param("workflowLeave") WorkflowLeave workflowLeave, @Param("deptId") Long deptId); + + /** + * 查询请假列表 + * + * @param workflowLeave 请假 + * @return 请假集合 + */ + public List selectWorkflowLeaveList(WorkflowLeave workflowLeave); + + + /** + * 新增请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + public int insertWorkflowLeave(WorkflowLeave workflowLeave); + + /** + * 修改请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + int updateWorkflowLeave(WorkflowLeave workflowLeave); + + /** + * 删除请假 + * + * @param id 请假ID + * @return 结果 + */ + int deleteWorkflowLeaveById(String id); + + /** + * 批量删除请假 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + int deleteWorkflowLeaveByIds(String[] ids); +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/IWorkflowLeaveService.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/IWorkflowLeaveService.java new file mode 100644 index 00000000..3e91edea --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/IWorkflowLeaveService.java @@ -0,0 +1,73 @@ +package com.xjs.workflow.leave.service; + + +import com.xjs.workflow.leave.domain.WorkflowLeave; + +import java.util.List; + +/** + * 请假Service接口 + * + * @author xiejs + * @since 2022-04-17 17:54:57 + */ +public interface IWorkflowLeaveService { + /** + * 查询请假 + * + * @param id 请假ID + * @return 请假 + */ + WorkflowLeave selectWorkflowLeaveById(String id); + + /** + * 查询请假列表 + * + * @param workflowLeave 请假 + * @return 请假集合 + */ + List selectWorkflowLeaveList(WorkflowLeave workflowLeave); + + /** + * 查询请假列表 + * + * @param workflowLeave 请假 + * @return 请假集合 + */ + List selectWorkflowLeaveAndTaskNameList(WorkflowLeave workflowLeave); + + /** + * 新增请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + int insertWorkflowLeave(WorkflowLeave workflowLeave); + + /** + * 修改请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + int updateWorkflowLeave(WorkflowLeave workflowLeave); + + /** + * 批量删除请假 + * + * @param ids 需要删除的请假ID + * @return 结果 + */ + int deleteWorkflowLeaveByIds(String[] ids); + + /** + * 删除请假信息 + * + * @param id 请假ID + * @return 结果 + */ + int deleteWorkflowLeaveById(String id); + + + WorkflowLeave selectWorkflowLeaveByInstanceId(String instanceId); +} diff --git a/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/impl/WorkflowLeaveServiceImpl.java b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/impl/WorkflowLeaveServiceImpl.java new file mode 100644 index 00000000..b16eae1b --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/java/com/xjs/workflow/leave/service/impl/WorkflowLeaveServiceImpl.java @@ -0,0 +1,155 @@ +package com.xjs.workflow.leave.service.impl; + +import com.ruoyi.common.core.text.UUID; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.RemoteUserService; +import com.xjs.workflow.leave.domain.WorkflowLeave; +import com.xjs.workflow.leave.mapper.WorkflowLeaveMapper; +import com.xjs.workflow.leave.service.IWorkflowLeaveService; +import org.activiti.api.process.model.ProcessInstance; +import org.activiti.api.process.model.builders.ProcessPayloadBuilder; +import org.activiti.api.process.runtime.ProcessRuntime; +import org.activiti.engine.TaskService; +import org.activiti.engine.task.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 请假Service业务层处理 + * + * @author xiejs + * @since 2022-04-17 17:55:10 + */ +@Service +public class WorkflowLeaveServiceImpl implements IWorkflowLeaveService { + + @Resource + private WorkflowLeaveMapper workflowLeaveMapper; + @Autowired + private ProcessRuntime processRuntime; + @Resource + private RemoteUserService remoteUserService; + @Autowired + private TaskService taskService; + + + /** + * 查询请假 + * + * @param id 请假ID + * @return 请假 + */ + @Override + public WorkflowLeave selectWorkflowLeaveById(String id) { + return workflowLeaveMapper.selectWorkflowLeaveById(id); + } + + /** + * 查询请假列表 + * + * @param workflowLeave 请假 + * @return 请假 + */ + @Override + public List selectWorkflowLeaveList(WorkflowLeave workflowLeave) { + return workflowLeaveMapper.selectWorkflowLeaveListByWorkflowLeaveAndDeptId(workflowLeave, SecurityUtils.getLoginUser().getSysUser().getDeptId()); + } + + /** + * 查询请假列表带任务状态 + * + * @param workflowLeave 请假 + * @return 请假 + */ + @Override + public List selectWorkflowLeaveAndTaskNameList(WorkflowLeave workflowLeave) { + List workflowLeaves = workflowLeaveMapper.selectWorkflowLeaveList(workflowLeave); + List collect = workflowLeaves.parallelStream().map(WorkflowLeave::getInstanceId).collect(Collectors.toList()); + if (collect != null && !collect.isEmpty()) { + List tasks = taskService.createTaskQuery().processInstanceIdIn(collect).list(); + workflowLeaves.forEach( + wl -> { + Task task = tasks.parallelStream().filter(t -> t.getProcessInstanceId().equals(wl.getInstanceId())).findAny().orElse(null); + if (task != null) { + wl.setTaskName(task.getName()); + } + } + ); + } + return workflowLeaves; + } + + /** + * 新增请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + @Override + public int insertWorkflowLeave(WorkflowLeave workflowLeave) { + + String id = UUID.randomUUID().toString(); + workflowLeave.setId(id); + workflowLeave.setCreateTime(DateUtils.getNowDate()); + String join = StringUtils.join(remoteUserService.selectUserNameByPostCodeAndDeptId("se", SecurityUtils.getLoginUser().getSysUser().getDeptId()), ","); + ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder + .start() + .withProcessDefinitionKey("leave") + .withName(workflowLeave.getTitle()) + .withBusinessKey(id) + .withVariable("deptLeader", join) + .build()); + workflowLeave.setInstanceId(processInstance.getId()); + workflowLeave.setState("0"); + workflowLeave.setCreateName(SecurityUtils.getLoginUser().getSysUser().getNickName()); + workflowLeave.setCreateBy(SecurityUtils.getUsername()); + workflowLeave.setCreateTime(DateUtils.getNowDate()); + return workflowLeaveMapper.insertWorkflowLeave(workflowLeave); + } + + /** + * 修改请假 + * + * @param workflowLeave 请假 + * @return 结果 + */ + @Override + public int updateWorkflowLeave(WorkflowLeave workflowLeave) { + workflowLeave.setUpdateTime(DateUtils.getNowDate()); + return workflowLeaveMapper.updateWorkflowLeave(workflowLeave); + } + + /** + * 批量删除请假 + * + * @param ids 需要删除的请假ID + * @return 结果 + */ + @Override + public int deleteWorkflowLeaveByIds(String[] ids) { + return workflowLeaveMapper.deleteWorkflowLeaveByIds(ids); + } + + /** + * 删除请假信息 + * + * @param id 请假ID + * @return 结果 + */ + @Override + public int deleteWorkflowLeaveById(String id) { + return workflowLeaveMapper.deleteWorkflowLeaveById(id); + } + + @Override + public WorkflowLeave selectWorkflowLeaveByInstanceId(String instanceId) { + + return workflowLeaveMapper.selectWorkflowLeaveByInstanceId(instanceId); + } +} diff --git a/xjs-business/xjs-business-workflow/src/main/resources/mapper/leave/WorkflowLeaveMapper.xml b/xjs-business/xjs-business-workflow/src/main/resources/mapper/leave/WorkflowLeaveMapper.xml new file mode 100644 index 00000000..5809ef5c --- /dev/null +++ b/xjs-business/xjs-business-workflow/src/main/resources/mapper/leave/WorkflowLeaveMapper.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + select id, type, title, reason, leave_start_time, leave_end_time, instance_id, state, create_name,create_by, create_time, update_time from workflow_leave + + + + + where create_by in (SELECT user_name FROM `sys_user` where dept_id in (SELECT dept_id FROM sys_dept WHERE dept_id = #{deptId} or find_in_set( #{deptId} , ancestors ) )) + and type = #{workflowLeave.type} + and title = #{workflowLeave.title} + and reason = #{workflowLeave.reason} + and leave_start_time = #{workflowLeave.leaveStartTime} + and leave_end_time = #{workflowLeave.leaveEndTime} + and instance_id = #{workflowLeave.instanceId} + and state = #{workflowLeave.state} + and create_name = #{workflowLeave.createName} + and create_by = #{workflowLeave.createBy} + order by create_time desc + + + + + + and type = #{type} + and title = #{title} + and reason = #{reason} + and leave_start_time = #{leaveStartTime} + and leave_end_time = #{leaveEndTime} + and instance_id = #{instanceId} + and state = #{state} + and create_name = #{createName} + and create_by = #{createBy} + + order by create_time desc + + + + + where id = #{id} + + + + where instance_id = #{instanceId} + + + + insert into workflow_leave + + id, + type, + title, + reason, + leave_start_time, + leave_end_time, + instance_id, + state, + create_name, + create_by, + create_time, + update_time, + + + #{id}, + #{type}, + #{title}, + #{reason}, + #{leaveStartTime}, + #{leaveEndTime}, + #{instanceId}, + #{state}, + #{createName}, + #{createBy}, + #{createTime}, + #{updateTime}, + + + + + update workflow_leave + + type = #{type}, + title = #{title}, + reason = #{reason}, + leave_start_time = #{leaveStartTime}, + leave_end_time = #{leaveEndTime}, + instance_id = #{instanceId}, + state = #{state}, + create_name = #{createName}, + create_by = #{createBy}, + create_time = #{createTime}, + update_time = #{updateTime}, + + where id = #{id} + + + + delete from workflow_leave where id = #{id} + + + + delete from workflow_leave where id in + + #{id} + + + + diff --git a/xjs-business/xjs-business-workflow/src/main/resources/mybatis/mybatis-config.xml b/xjs-business/xjs-business-workflow/src/main/resources/mybatis/mybatis-config.xml index e8b52be8..ab1d9503 100644 --- a/xjs-business/xjs-business-workflow/src/main/resources/mybatis/mybatis-config.xml +++ b/xjs-business/xjs-business-workflow/src/main/resources/mybatis/mybatis-config.xml @@ -3,7 +3,7 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> - + @@ -11,5 +11,5 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" - +
无法显示bpms2.0