diff --git a/packages/ding-flow/package.json b/packages/ding-flow/package.json index ee7339d..9d3166e 100644 --- a/packages/ding-flow/package.json +++ b/packages/ding-flow/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@miyue-mma/shared": "workspace:^", + "bpmn-moddle": "^9.0.1", "normalize.css": "^8.0.1", "tippy.js": "^6.3.7" }, diff --git a/packages/ding-flow/src/App.vue b/packages/ding-flow/src/App.vue index 395d04e..dd4d5d4 100644 --- a/packages/ding-flow/src/App.vue +++ b/packages/ding-flow/src/App.vue @@ -6,7 +6,9 @@ import DingFlow from '@/components/DingFlow.vue' import type { BaseNode, FlowDirection, SubprocessNode } from '@/types' import TippyPopover from '@/components/base/TippyPopover.vue' import { createPresetProcess } from '@/utils/element-utils' -import { toJson } from '@/utils/transform' +import { transformToJson, transformToXML } from '@/utils/transform' +import { moddle } from '@/bpmn-moddle' +import mockXml from '@/utils/mock-xml' const dir = ref('vertical') const dingFlowRef = ref>() @@ -40,7 +42,19 @@ function center() { const processData = ref(createPresetProcess()) function getData() { - console.log(toJson(toRaw(processData.value))) + console.log(transformToJson(toRaw(processData.value))) +} + +async function parseXML() { + // moddle.parseXML(mockXml) + const parseResult = await moddle.fromXML(mockXml, 'bpmn:Definitions') + console.log(parseResult) +} +async function generateXML() { + // const definitions = moddle.create('bpmn:Definitions') + // definitions.rootElements = [createBpmnProcess({ name: 'ceshi', id: ids('process') })] + const { xml } = await transformToXML(processData.value) + console.log(xml) } @@ -63,6 +77,12 @@ function getData() { 打印数据 + + 测试xml解析 + + + 测试xml生成 + - + diff --git a/packages/ding-flow/src/bpmn-moddle/flowable.json b/packages/ding-flow/src/bpmn-moddle/flowable.json new file mode 100644 index 0000000..96ff89a --- /dev/null +++ b/packages/ding-flow/src/bpmn-moddle/flowable.json @@ -0,0 +1,1369 @@ +{ + "name": "Flowable", + "uri": "http://flowable.org/bpmn", + "prefix": "flowable", + "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", "bpmn:SignalEventDefinition"] + } + }, + { + "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": "Scope", + "extends": ["bpmn:Signal"], + "properties": [ + { + "name": "scope", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ErrorEventDefinitionExtension", + "isAbstract": true, + "extends": ["bpmn:ErrorEventDefinition"], + "properties": [ + { + "name": "errorCodeVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "errorMessageVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "errorVariableLocalScope", + "isAttr": true, + "type": "Boolean" + }, + { + "name": "errorVariableTransient", + "isAttr": true, + "type": "Boolean" + } + ] + }, + { + "name": "ErrorEventDefinition", + "superClass": ["bpmn:ErrorEventDefinition", "Element"], + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + } + ], + "meta": { + "allowedIn": ["bpmn:ServiceTask"] + } + }, + { + "name": "Error", + "isAbstract": true, + "extends": ["bpmn:Error"], + "properties": [ + { + "name": "flowable:errorMessage", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FormSupported", + "isAbstract": true, + "extends": ["bpmn:StartEvent", "bpmn:UserTask"], + "properties": [ + { + "name": "formKey", + "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": "autoStoreVariables", + "isAttr": true, + "type": "Boolean" + }, + { + "name": "resource", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Process", + "isAbstract": true, + "extends": ["bpmn:Process"], + "properties": [ + { + "name": "candidateStarterGroups", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateStarterUsers", + "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": "priority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "CallActivity", + "extends": ["bpmn:CallActivity"], + "properties": [ + { + "name": "inheritVariables", + "isAttr": true, + "type": "Boolean" + }, + { + "name": "calledElementType", + "isAttr": true, + "type": "String" + }, + { + "name": "processInstanceName", + "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": "ExternalCapable", + "extends": ["flowable:ServiceTaskLike"], + "properties": [ + { + "name": "type", + "isAttr": true, + "type": "String" + }, + { + "name": "topic", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "TaskPriorized", + "extends": ["bpmn:Process", "flowable: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": ["flowable:ServiceTaskLike"] + }, + "properties": [ + { + "name": "inputOutput", + "type": "InputOutput" + }, + { + "name": "connectorId", + "type": "String" + } + ] + }, + { + "name": "InputOutput", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:FlowNode", "flowable: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": ["Element"], + "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": [ + "flowable:ServiceTaskLike", + "flowable:ExecutionListener", + "flowable: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": ["flowable:AsyncCapable"], + "properties": [ + { + "name": "collection", + "isAttr": true, + "type": "String" + }, + { + "name": "elementVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FailedJobRetryTimeCycle", + "superClass": ["Element"], + "meta": { + "allowedIn": ["flowable: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": "EventListener", + "superClass": [ + "Element" + ], + "meta": { + "allowedIn": [ + "bpmn:Process" + ] + }, + "properties": [ + { + "name": "events", + "isAttr": true, + "type": "String" + }, + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "throwEvent", + "isAttr": true, + "type": "String" + }, + { + "name": "entityType", + "isAttr": true, + "type": "String" + }, + { + "name": "signalName", + "isAttr": true, + "type": "String" + }, + { + "name": "errorCode", + "isAttr": true, + "type": "String" + }, + { + "name": "messageName", + "isAttr": true, + "type": "String" + } + ] + }, + { + "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": "ConditionalEventDefinitionExtension", + "isAbstract": true, + "extends": ["bpmn:ConditionalEventDefinition"], + "properties": [ + { + "name": "variableName", + "isAttr": true, + "type": "String" + }, + { + "name": "variableEvents", + "isAttr": true, + "type": "String" + } + ] + }, + + { + "name": "AssigneeType", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "MultiCompletionCondition", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:Activity"] + }, + "properties": [ + { + "name": "type", + "type": "String", + "isAttr": true + }, + { + "name": "conditionType", + "type": "String", + "isAttr": true + }, + { + "name": "num", + "type": "Number", + "isAttr": true + }, + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "IdmAssignee", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "IdmCandidateUsers", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask", "bpmn:Process"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "IdmCandidateGroups", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask", "bpmn:Process"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "NextSequenceFlow", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "NextUser", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "ModelBpmnExtension", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "ProcessNameExp", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:Process"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "NodeFormExp", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:Event", "bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "NodeFormType", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:Event", "bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "StaticAssigneeVariables", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:Event", "bpmn:UserTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "MultiInstanceVariables", + "superClass": ["Element"], + "meta": { + "allowedIn": ["*"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "ServiceTask", + "extends": ["bpmn:ServiceTask"], + "properties": [ + { + "name": "parallelInSameTransaction", + "type": "Boolean", + "isAttr": true + } + ] + }, + + { + "name": "TimeDate", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:BoundaryEvent", + "bpmn:TimerEventDefinition", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "BoundaryEvent", + "extends": ["bpmn:BoundaryEvent"], + "properties": [ + { + "name": "timerEventDefinition", + "isBody": true, + "type": "flowable:TimerEventDefinition" + }, + { + "name": "cancelActivity", + "isAttr": true, + "type": "Boolean", + "redefines": "bpmn:BoundaryEvent#cancelActivity" + } + ] + }, + { + "name": "TimerEventDefinition", + "superClass": ["TimerEventDefinition"], + "meta": { + "allowedIn": [ + "bpmn:BoundaryEvent", + "bpmn:TimerEventDefinition", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "TimeDuration", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:BoundaryEvent", + "bpmn:TimerEventDefinition", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "TimeCycle", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:BoundaryEvent", + "bpmn:TimerEventDefinition", + "flowable:endDate", + "bpmn:UserTask" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + }, + { + "name": "endDate", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "SkipUserTask", + "extends": ["bpmn:UserTask"], + "properties": [ + { + "name": "skipExpression", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "TransferToUsers", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:ServiceTask"] + }, + "properties": [ + { + "name": "body", + "type": "String", + "isBody": true + } + ] + }, + { + "name": "FormFieldValidation", + "extends": ["bpmn:UserTask", "bpmn:StartEvent"], + "properties": [ + { + "name": "formFieldValidation", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "DataObject", + "extends": ["bpmn:DataObject"], + "meta": { + "allowedIn": ["bpmn:Process", "bpmn:SubProcess"] + }, + "properties": [ + { + "name": "itemSubjectRef", + "type": "String", + "isAttr": true, + "redefines": "bpmn:DataObject#itemSubjectRef" + } + ] + }, + { + "name": "InterruptingStartEvent", + "extends": ["bpmn:StartEvent"], + "properties": [ + { + "name": "isInterrupting", + "isAttr": true, + "type": "Boolean", + "redefines": "bpmn:StartEvent#isInterrupting" + } + ] + }, + { + "name": "VariableListenerEventDefinition", + "superClass": ["Element"], + "meta": { + "allowedIn": ["*"] + }, + "properties": [ + { + "name": "variableName", + "type": "String", + "isAttr": true + }, + { + "name": "variableChangeType", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "TerminateEventDefinition", + "extends": ["bpmn:TerminateEventDefinition"], + "properties": [ + { + "name": "terminateAll", + "isAttr": true, + "type": "Boolean" + } + ] + }, + { + "name": "AdHoc", + "extends": ["bpmn:AdHocSubProcess"], + "properties": [ + { + "name": "cancelRemainingInstances", + "isAttr": true, + "type": "Boolean", + "redefines": "bpmn:AdHocSubProcess#cancelRemainingInstances" + } + ] + } + ], + "emumerations": [] +} diff --git a/packages/ding-flow/src/bpmn-moddle/index.ts b/packages/ding-flow/src/bpmn-moddle/index.ts new file mode 100644 index 0000000..445ac95 --- /dev/null +++ b/packages/ding-flow/src/bpmn-moddle/index.ts @@ -0,0 +1,11 @@ +/** + * @desc index + * @author MiyueFE + * @since 2024/7/31 下午4:42 + */ +import BpmnModdle from 'bpmn-moddle' +import flowableDescriptor from './flowable.json' + +export const moddle = new BpmnModdle({ + flowable: flowableDescriptor, +}) diff --git a/packages/ding-flow/src/components.d.ts b/packages/ding-flow/src/components.d.ts index 3a1b722..99e1e54 100644 --- a/packages/ding-flow/src/components.d.ts +++ b/packages/ding-flow/src/components.d.ts @@ -19,6 +19,7 @@ declare module 'vue' { RouterView: typeof import('vue-router')['RouterView'] ServiceNode: typeof import('./components/nodes/ServiceNode.vue')['default'] SubprocessNode: typeof import('./components/nodes/SubprocessNode.vue')['default'] + SubProcessNode: typeof import('./components/nodes/SubProcessNode.vue')['default'] TaskNode: typeof import('./components/nodes/TaskNode.vue')['default'] TippyPopover: typeof import('./components/base/TippyPopover.vue')['default'] } diff --git a/packages/ding-flow/src/components/base/NodeWrapper.vue b/packages/ding-flow/src/components/base/NodeWrapper.vue index 5e55daf..f29c4dd 100644 --- a/packages/ding-flow/src/components/base/NodeWrapper.vue +++ b/packages/ding-flow/src/components/base/NodeWrapper.vue @@ -17,6 +17,7 @@ import { } from '@/utils/element-utils' import type { GlobalConfigKey } from '@/utils/global-config' import { getGlobalConfig } from '@/utils/global-config' +import { capitalize } from '@/utils/tools' defineOptions({ name: 'NodeWrapper' }) @@ -117,7 +118,7 @@ function emitContextmenu() { } function transformNodeName(node: BaseNode): string { - return `${node.type}-node` + return `${capitalize(node.type)}Node` } diff --git a/packages/ding-flow/src/styles/variable.scss b/packages/ding-flow/src/styles/variable.scss index d516cf7..8a077a8 100644 --- a/packages/ding-flow/src/styles/variable.scss +++ b/packages/ding-flow/src/styles/variable.scss @@ -31,13 +31,8 @@ --expression-height: var(--common-height); } -body,body[arco-theme=dark] { - --color-line-rgb: 250, 250, 250; - --color-line: rgb(var(--color-line-rgb)); -} body { - --color-line-rgb: 5, 5, 5; - --color-line: rgb(var(--color-line-rgb)); + --color-line: var(--color-text-2); } /* 主题来源:arco-design 懂车帝PC2B 主题 {@link https://arco.design/themes/preview/58}*/ diff --git a/packages/ding-flow/src/types/bpmn-moddle.d.ts b/packages/ding-flow/src/types/bpmn-moddle.d.ts new file mode 100644 index 0000000..957e5c1 --- /dev/null +++ b/packages/ding-flow/src/types/bpmn-moddle.d.ts @@ -0,0 +1,34 @@ +/** + * @desc bpmn-moddle.d + * @author MiyueFE + * @since 2024/7/31 下午5:06 + */ + +declare module 'bpmn-moddle' { + import type { BpmnElement, BpmnModdleElement, BpmnRoot } from '@/types/bpmn-node' + + export interface ParseReference { + id: string + property: string + element: BpmnElement + } + + export interface ParseResult { + rootElement: BpmnRoot + references: ParseReference[] + warnings: any[] + elementsById: Record + } + + export default class BpmnModdle { + constructor(options: Record) + + fromXML(xmlStr: string, typeName: string = 'bpmn:Definitions', options?: Record): Promise + toXML(element: BpmnElement, options?: { format?: boolean, preamble?: boolean }): Promise<{ xml: string }> + + create(type: string, props?: Record): T + getType(descriptor: string | object): Record + createAny(name: string, nsUri: string, properties: Record): BpmnModdleElement + hasType(element: BpmnElement, type: string): boolean + } +} diff --git a/packages/ding-flow/src/types/bpmn-node.ts b/packages/ding-flow/src/types/bpmn-node.ts new file mode 100644 index 0000000..8b030f0 --- /dev/null +++ b/packages/ding-flow/src/types/bpmn-node.ts @@ -0,0 +1,33 @@ +/** + * @desc bpmn-node + * @author MiyueFE + * @since 2024/7/31 下午4:57 + */ + +export interface BpmnBase { + $type: string +} + +export interface BpmnModdleElement extends BpmnBase { +} + +export interface BpmnElement extends BpmnModdleElement { + id: string + name: string + extensionElements?: BpmnModdleElement[] +} + +export interface BpmnFlow extends BpmnElement { + sourceRef: BpmnElement + targetRef: BpmnElement +} + +export interface BpmnDefinitions extends BpmnElement { + targetNamespace: string + rootElements: BpmnRoot[] +} + +export interface BpmnRoot extends BpmnElement { + isExecutable?: boolean + flowElements: BpmnElement[] +} diff --git a/packages/ding-flow/src/utils/element-utils.ts b/packages/ding-flow/src/utils/element-utils.ts index 4dc70ac..b820571 100644 --- a/packages/ding-flow/src/utils/element-utils.ts +++ b/packages/ding-flow/src/utils/element-utils.ts @@ -46,6 +46,14 @@ export const DEFAULT_NAME_MAP = { subprocess: '子流程', expression: '条件', } +export const DEFAULT_BPMN_TYPE_MAP = { + event: 'event', + gateway: 'exclusiveGateway', + task: 'task', + service: 'serviceTask', + subprocess: 'subProcess', + expression: 'sequenceFlow', +} /** * 创建节点 */ @@ -98,7 +106,7 @@ export function createNode( $prev: undefined, $next: undefined, $parent: parent, - businessData: bo || {}, + businessData: { $type: DEFAULT_BPMN_TYPE_MAP[type] || type, ...(bo || {}) }, } switch (type) { diff --git a/packages/ding-flow/src/utils/mock-xml.ts b/packages/ding-flow/src/utils/mock-xml.ts new file mode 100644 index 0000000..8b5d891 --- /dev/null +++ b/packages/ding-flow/src/utils/mock-xml.ts @@ -0,0 +1,69 @@ +/** + * @desc mock-xml + * @author MiyueFE + * @since 2024/7/31 下午4:36 + */ + +export default ` + + + + [{"id":"1","name":"易烊千玺","code":"10000","email":"liuwenjun05101@163.com","mobile":null,"companyName":"中国石化","deptName":"领导班子"}] + + + Flow_1tdjwug + + + + static + + Flow_1tdjwug + Flow_0dfn1pl + Flow_1i2hinq + + + + Flow_0dfn1pl + Flow_0cnsdh3 + + + + + static + [] + + Flow_0cnsdh3 + Flow_1ab8ejp + Flow_1uul2n5 + + + + Flow_1i2hinq + Flow_1ab8ejp + + Flow_1nlyisl + + + + static + + Flow_1nlyisl + Flow_0hjbatw + + + + Flow_0hjbatw + + + + + + + Flow_1uul2n5 + + + + + + +` diff --git a/packages/ding-flow/src/utils/tools.ts b/packages/ding-flow/src/utils/tools.ts new file mode 100644 index 0000000..be80291 --- /dev/null +++ b/packages/ding-flow/src/utils/tools.ts @@ -0,0 +1,12 @@ +/** + * @desc tools + * @author MiyueFE + * @since 2024/8/1 下午4:32 + */ + +export function capitalize(str: string): string { + if (!str || str.length === 0) + return '' + const lower = str + return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length) +} diff --git a/packages/ding-flow/src/utils/transform.ts b/packages/ding-flow/src/utils/transform.ts index 1b05dd5..e6da614 100644 --- a/packages/ding-flow/src/utils/transform.ts +++ b/packages/ding-flow/src/utils/transform.ts @@ -4,6 +4,10 @@ * @since 2024/7/30 下午9:16 */ import type { BaseNode, BaseNodeBO, GatewayNode, SubprocessNode } from '@/types' +import { moddle } from '@/bpmn-moddle' +import type { BpmnDefinitions, BpmnElement, BpmnFlow, BpmnRoot } from '@/types/bpmn-node' +import { capitalize } from '@/utils/tools' +import { createNode } from '@/utils/element-utils' interface NodeJson { id: string @@ -25,33 +29,8 @@ interface NodeJson { $defaultRef?: BaseNode['id'] } -export function toJson(node: BaseNode): NodeJson | undefined { - if (!node) - return undefined - - const result: NodeJson = nodeToJson(node) - - let parent: NodeJson = result - let cur: BaseNode | undefined = node.$next - while (cur) { - const nextNode = nodeToJson(cur) - - // 特殊处理子流程 - if (cur.type === 'subprocess') { - console.log(cur) - nextNode.childNode = toJson((cur as SubprocessNode).$start as BaseNode) - } - - parent.nextNode = nextNode - - cur = cur.$next - parent = nextNode - } - - return result -} - -export function nodeToJson(node: BaseNode) { +// 转为可用 json +export function transformNodeToJson(node: BaseNode) { const { id, type, @@ -68,7 +47,7 @@ export function nodeToJson(node: BaseNode) { const $nextRef = $next?.id const $prevRef = $prev?.id const $parentRef = $parent?.id - const expressionRefs = expressions?.map(e => toJson(e)!) + const expressionRefs = expressions?.map(e => transformToJson(e)!) const $startRef = $start?.id const $defaultRef = $default?.id @@ -79,6 +58,10 @@ export function nodeToJson(node: BaseNode) { businessData, } + if (expressionRefs) { + result.expressionRefs = expressionRefs + } + if ($nextRef) { result.$nextRef = $nextRef } @@ -91,9 +74,6 @@ export function nodeToJson(node: BaseNode) { if ($parentRef) { result.$parentRef = $parentRef } - if (expressionRefs) { - result.expressionRefs = expressionRefs - } if ($startRef) { result.$startRef = $startRef } @@ -103,3 +83,131 @@ export function nodeToJson(node: BaseNode) { return result } +export function transformToJson(node: BaseNode): NodeJson | undefined { + if (!node) + return undefined + + const result: NodeJson = transformNodeToJson(node) + + let parent: NodeJson = result + let cur: BaseNode | undefined = node.$next + while (cur) { + const nextNode = transformNodeToJson(cur) + + // 特殊处理子流程 + if (cur.type === 'subprocess') { + nextNode.childNode = transformToJson((cur as SubprocessNode).$start as BaseNode) + } + + parent.nextNode = nextNode + + cur = cur.$next + parent = nextNode + } + + return result +} + +// 转为符合绘图数据格式的互相引用对象 +export function parseJsonToNode(node: NodeJson) { + const { id, name, businessData, type } = node + + // @ts-expect-error + const result: BaseNode = createNode(type, undefined, name, businessData) + result.id = id + + return result +} +export function parseJsonToNodeTree(node: NodeJson) { + if (!node) + return undefined + + const result: BaseNode = parseJsonToNode(node) + + return result +} + +/* bpmn 相关 */ +type BpmnProps = Record + +export function createBpmnDefinitions() { + const defs = moddle.create('bpmn:Definitions') + defs.rootElements = [] + return defs +} + +export function createBpmnProcess(props: BpmnProps) { + const process = moddle.create('bpmn:Process', { ...props }) + process.flowElements = [] + return process +} + +export function createBpmnSubprocess(props: BpmnProps) { + const process = moddle.create('bpmn:SubProcess', { ...props }) + process.flowElements = [] + return process +} + +export function createBpmnElement(type: string, props: BpmnProps) { + return moddle.create(`bpmn:${capitalize(type)}`, props) +} + +export function createBpmnSequenceFlow(source: BpmnElement, target: BpmnElement, props: BpmnProps = {}) { + const flow = moddle.create(`bpmn:SequenceFlow`, props) + flow.sourceRef = source + flow.targetRef = target + return flow +} + +let lastBpmnNode: BpmnElement | undefined + +function transformNode(node: BaseNode, parentArray: BpmnElement[]) { + const { id, name, type, businessData } = node + let current: BpmnElement + if (type === 'subprocess') { + current = transformSubprocessNode(node as SubprocessNode) + } + else { + current = createBpmnElement(businessData.$type || 'task', { id, name }) + } + + if (lastBpmnNode) { + parentArray.push(createBpmnSequenceFlow(lastBpmnNode, current)) + } + + lastBpmnNode = current + + return current +} + +function transformSubprocessNode(node: SubprocessNode): BpmnRoot { + const { id, name, $start } = node + const subprocess = createBpmnSubprocess({ id, name }) + let cur: BaseNode | undefined = $start + while (cur) { + if (cur.type === 'subprocess') { + subprocess.flowElements.push(transformSubprocessNode(cur as SubprocessNode)) + } + else { + subprocess.flowElements.push(transformNode(cur, subprocess.flowElements)) + } + cur = cur.$next + } + + return subprocess +} + +export async function transformToXML(node: BaseNode): Promise<{ xml: string }> { + const definitions = createBpmnDefinitions() + const process = createBpmnProcess({}) + definitions.rootElements = [process] + + let cur: BaseNode | undefined = node + while (cur) { + process.flowElements.push(transformNode(cur, process.flowElements)) + cur = cur.$next + } + + lastBpmnNode = undefined + return await moddle.toXML(definitions, { format: true, preamble: true }) +} diff --git a/packages/ding-flow/src/utils/uuid.ts b/packages/ding-flow/src/utils/uuid.ts index a49d5e5..1071b38 100644 --- a/packages/ding-flow/src/utils/uuid.ts +++ b/packages/ding-flow/src/utils/uuid.ts @@ -1,10 +1,10 @@ import Ids from 'ids' -const idsCreator = new Ids() +const idsCreator = new Ids([32, 36, 1]) export function ids(prefix: string, simple: boolean = true) { if (simple) { - return idsCreator.nextPrefixed(prefix) + return idsCreator.nextPrefixed(`${prefix}-`) } if (typeof crypto.randomUUID === 'function') { diff --git a/packages/shared/lib/utils/string.ts b/packages/shared/lib/utils/string.ts index 079a5db..8a6141b 100644 --- a/packages/shared/lib/utils/string.ts +++ b/packages/shared/lib/utils/string.ts @@ -24,7 +24,7 @@ export function slash(str: string) { export function capitalize(str: string): string { if (!str || str.length === 0) return '' - const lower = str.toLowerCase() + const lower = str return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length) } @@ -107,14 +107,14 @@ export function template(str: string, ...args: any[]): string { if (isObject(firstArg)) { const vars = firstArg as Record return str.replace( - /{([\w\d]+)}/g, + /\{(\w+)\}/g, (_, key) => vars[key] || ((typeof fallback === 'function' ? fallback(key) : fallback) ?? key), ) } else { - return str.replace(/{(\d+)}/g, (_, key) => { + return str.replace(/\{(\d+)\}/g, (_, key) => { const index = Number(key) if (Number.isNaN(index)) return key @@ -155,6 +155,6 @@ export function randomId(length: number): string { * 转对象路径数组 */ export function toPathArray(path: string): string[] { - const regex = /\[(\d+)]/g + const regex = /\[(\d+)\]/g return path.replace(regex, (_, number) => `.${number}.`).split('.').filter(s => s.trim()) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6edd202..b01c50a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,6 +109,9 @@ importers: '@miyue-mma/shared': specifier: workspace:^ version: link:../shared + bpmn-moddle: + specifier: ^9.0.1 + version: 9.0.1 normalize.css: specifier: ^8.0.1 version: 8.0.1 @@ -1415,6 +1418,10 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bpmn-moddle@9.0.1: + resolution: {integrity: sha512-jO2P5RBx0cZCCd+imqhpNE5anttaYuGd71u76NEA/qMZwJSW1t5ETAtw9/E2InfiPU2w0TR8oxPyopJXRc9VQg==} + engines: {node: '>= 18'} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2383,6 +2390,9 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + min-dash@4.2.1: + resolution: {integrity: sha512-to+unsToePnm7cUeR9TrMzFlETHd/UXmU+ELTRfWZj5XGT41KF6X3L233o3E/GdEs3sk2Tbw/lOLD1avmWkg8A==} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -2411,6 +2421,15 @@ packages: mlly@1.7.1: resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} + moddle-xml@11.0.0: + resolution: {integrity: sha512-L3Sseepfcq9Uy0iIfqEDTXSoYLva1Y/JGbN/4AMOeQ6cqbu8Ma/SDJIdOFm7smsAa64j2z3SwCGG3FIilQVnUg==} + engines: {node: '>= 18'} + peerDependencies: + moddle: '>= 6.2.0' + + moddle@7.0.0: + resolution: {integrity: sha512-Hpte2hfKDwoZWPvDngsEHjloPnO+sKMUVkAPc0r9PrpnVLqsyPUTV0ZQU8CAp87YmRZ9QzeQMJxdKbaP9vEIKA==} + mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} @@ -2751,6 +2770,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + saxen@10.0.0: + resolution: {integrity: sha512-RXsmWok/SAWqOG/f5ADEz51DN9WtZEzqih3e08ranldcaXekxjx8NBKjGh/y5hlowjo0JH/LekBu6gtPFD1G6g==} + engines: {node: '>= 18'} + scroll-into-view-if-needed@2.2.31: resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} @@ -4662,6 +4685,12 @@ snapshots: boolbase@1.0.0: {} + bpmn-moddle@9.0.1: + dependencies: + min-dash: 4.2.1 + moddle: 7.0.0 + moddle-xml: 11.0.0(moddle@7.0.0) + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -5708,6 +5737,8 @@ snapshots: mimic-fn@4.0.0: {} + min-dash@4.2.1: {} + min-indent@1.0.1: {} minimatch@3.0.8: @@ -5742,6 +5773,16 @@ snapshots: pkg-types: 1.1.1 ufo: 1.5.3 + moddle-xml@11.0.0(moddle@7.0.0): + dependencies: + min-dash: 4.2.1 + moddle: 7.0.0 + saxen: 10.0.0 + + moddle@7.0.0: + dependencies: + min-dash: 4.2.1 + mrmime@2.0.0: {} ms@2.1.2: {} @@ -6075,6 +6116,8 @@ snapshots: immutable: 4.3.6 source-map-js: 1.2.0 + saxen@10.0.0: {} + scroll-into-view-if-needed@2.2.31: dependencies: compute-scroll-into-view: 1.0.20