ruoyi-nbcio-plus基于vue3的flowable流程设计器主界面升级修改

更多ruoyi-nbcio功能请看演示系统

gitee源代码地址

前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

演示地址:RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/

更多nbcio-boot功能请看演示系统 

gitee源代码地址

后端代码: https://gitee.com/nbacheng/nbcio-boot

前端代码:https://gitee.com/nbacheng/nbcio-vue.git

在线演示(包括H5) : http://122.227.135.243:9888

1、原有ProcessDesigner.vue的vue2代码如下:

<template><div class="my-process-designer"><div class="my-process-designer__header"><slot name="control-header"></slot><template v-if="!$slots['control-header']"><el-button-group key="file-control"><el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-edit-outline" @click="onSave">保存流程</el-button><el-button :size="headerButtonSize" :type="headerButtonType" :icon="FolderOpened" @click="$refs.refFile.click()">打开文件</el-button><el-tooltip effect="light"><template #content><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsXml()">下载为XML文件</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsSvg()">下载为SVG文件</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsBpmn()">下载为BPMN文件</el-button></template><el-button :size="headerButtonSize" :type="headerButtonType" :icon="Download">下载文件</el-button></el-tooltip><el-tooltip effect="light"><template #content><el-button :size="headerButtonSize" type="primary" @click="previewProcessXML">预览XML</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="previewProcessJson">预览JSON</el-button></template><el-button :size="headerButtonSize" :type="headerButtonType" :icon="View">预览</el-button></el-tooltip><el-tooltip v-if="simulation" effect="light" :content="this.simulationStatus ? '退出模拟' : '开启模拟'"><el-button :size="headerButtonSize" :type="headerButtonType" :icon="Cpu" @click="processSimulation">模拟</el-button></el-tooltip></el-button-group><el-button-group key="align-control"><el-tooltip effect="light" content="向左对齐"><el-button :size="headerButtonSize" class="align align-left" :icon="Histogram" @click="elementsAlign('left')" /></el-tooltip><el-tooltip effect="light" content="向右对齐"><el-button :size="headerButtonSize" class="align align-right" :icon="Histogram" @click="elementsAlign('right')" /></el-tooltip><el-tooltip effect="light" content="向上对齐"><el-button :size="headerButtonSize" class="align align-top" :icon="Histogram" @click="elementsAlign('top')" /></el-tooltip><el-tooltip effect="light" content="向下对齐"><el-button :size="headerButtonSize" class="align align-bottom" :icon="Histogram" @click="elementsAlign('bottom')" /></el-tooltip><el-tooltip effect="light" content="水平居中"><el-button :size="headerButtonSize" class="align align-center" :icon="Histogram" @click="elementsAlign('center')" /></el-tooltip><el-tooltip effect="light" content="垂直居中"><el-button :size="headerButtonSize" class="align align-middle" :icon="Histogram" @click="elementsAlign('middle')" /></el-tooltip></el-button-group><el-button-group key="scale-control"><el-tooltip effect="light" content="缩小视图"><el-button :size="headerButtonSize" :disabled="defaultZoom < 0.2" :icon="ZoomOut" @click="processZoomOut()" /></el-tooltip><el-button :size="headerButtonSize">{{ Math.floor(this.defaultZoom * 10 * 10) + "%" }}</el-button><el-tooltip effect="light" content="放大视图"><el-button :size="headerButtonSize" :disabled="defaultZoom > 4" :icon="ZoomIn" @click="processZoomIn()" /></el-tooltip><el-tooltip effect="light" content="重置视图并居中"><el-button :size="headerButtonSize" :icon="ScaleToOriginal" @click="processReZoom()" /></el-tooltip></el-button-group><el-button-group key="stack-control"><el-tooltip effect="light" content="撤销"><el-button :size="headerButtonSize" :disabled="!revocable" :icon="RefreshLeft" @click="processUndo()" /></el-tooltip><el-tooltip effect="light" content="恢复"><el-button :size="headerButtonSize" :disabled="!recoverable" :icon="RefreshRight" @click="processRedo()" /></el-tooltip><el-tooltip effect="light" content="重新绘制"><el-button :size="headerButtonSize" :icon="Refresh" @click="processRestart" /></el-tooltip></el-button-group></template><!-- 用于打开本地文件--><input type="file" id="files" ref="refFile" style="display: none" accept=".xml, .bpmn" @change="importLocalFile" /></div><div class="my-process-designer__container"><div class="my-process-designer__canvas" ref="bpmn-canvas"></div></div><el-dialog title="预览" width="60%" v-model="previewModelVisible" append-to-body destroy-on-close><highlightjs :language="previewType" :code="previewResult" style="height: 80vh" /></el-dialog><!--<el-dialog :title="`预览${previewType}`" width="60%" v-model="previewModelVisible" append-to-body destroy-on-close><Codemirrorv-model:value="previewResult":options="cmOptions"border:height="700"/></el-dialog>--></div>
</template><script>
import { Histogram, Cpu, Refresh, RefreshLeft, RefreshRight, ZoomOut, ZoomIn, View, Download, FolderOpened, ScaleToOriginal } from '@element-plus/icons-vue'
import BpmnModeler from "bpmn-js/lib/Modeler";
import DefaultEmptyXML from "./plugins/defaultEmpty";
// 翻译方法
import customTranslate from "./plugins/translate/customTranslate";
import translationsCN from "./plugins/translate/zh";
// 模拟流转流程
import tokenSimulation from "bpmn-js-token-simulation";
// 标签解析构建器
// import bpmnPropertiesProvider from "bpmn-js-properties-panel/lib/provider/bpmn";
// 标签解析 Moddle
import camundaModdleDescriptor from './plugins/descriptor/camundaDescriptor.json';
import activitiModdleDescriptor from './plugins/descriptor/activitiDescriptor.json';
import flowableModdleDescriptor from './plugins/descriptor/flowableDescriptor.json';
// 标签解析 Extension
import camundaModdleExtension from './plugins/extension-moddle/camunda';
import activitiModdleExtension from './plugins/extension-moddle/activiti';
import flowableModdleExtension from './plugins/extension-moddle/flowable';
// 引入json转换与高亮
// import X2JS from "x2js";
import convert from "xml-js";import Codemirror from 'codemirror-editor-vue3';
import 'codemirror/theme/monokai.css'
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/xml/xml.js';export default {name: "MyProcessDesigner",componentName: "MyProcessDesigner",components: {Codemirror},setup() {return {Histogram, Cpu, Refresh, RefreshLeft, RefreshRight, ZoomOut, ZoomIn, View, Download, FolderOpened, ScaleToOriginal}},emits: ['destroy', 'init-finished', 'commandStack-changed', 'update:modelValue', 'change', 'canvas-viewbox-changed', 'element-click'],props: {modelValue: String, // xml 字符串processId: String,processName: String,translations: Object, // 自定义的翻译文件options: {type: Object,default: () => ({})}, // 自定义的翻译文件additionalModel: [Object, Array], // 自定义modelmoddleExtension: Object, // 自定义moddleonlyCustomizeAddi: {type: Boolean,default: false},onlyCustomizeModdle: {type: Boolean,default: false},simulation: {type: Boolean,default: true},keyboard: {type: Boolean,default: true},prefix: {type: String,default: "flowable"},events: {type: Array,default: () => ["element.click"]},headerButtonSize: {type: String,default: "small",validator: value => ["default", "medium", "small", "mini"].indexOf(value) !== -1},headerButtonType: {type: String,default: "primary",validator: value => ["default", "primary", "success", "warning", "danger", "info"].indexOf(value) !== -1}},data() {return {defaultZoom: 1,previewModelVisible: false,simulationStatus: false,previewResult: "",previewType: "xml",recoverable: false,revocable: false,cmOptions: {mode: 'xml', // 语言模式theme: 'monokai', // 主题lineNumbers: true, // 显示行号smartIndent: true, // 智能缩进readOnly: true,indentUnit: 2, // 智能缩进单位为4个空格长度foldGutter: true, // 启用行槽中的代码折叠styleActiveLine: true // 显示选中行的样式}};},computed: {additionalModules() {const Modules = [];// 仅保留用户自定义扩展模块if (this.onlyCustomizeAddi) {if (Object.prototype.toString.call(this.additionalModel) === "[object Array]") {return this.additionalModel || [];}return [this.additionalModel];}// 插入用户自定义扩展模块if (Object.prototype.toString.call(this.additionalModel) === "[object Array]") {Modules.push(...this.additionalModel);} else {this.additionalModel && Modules.push(this.additionalModel);}// 翻译模块const TranslateModule = {translate: ["value", customTranslate(this.translations || translationsCN)]};Modules.push(TranslateModule);// 模拟流转模块if (this.simulation) {Modules.push(tokenSimulation);}// 根据需要的流程类型设置扩展元素构建模块// if (this.prefix === "bpmn") {//   Modules.push(bpmnModdleExtension);// }if (this.prefix === "camunda") {Modules.push(camundaModdleExtension);}if (this.prefix === "flowable") {Modules.push(flowableModdleExtension);}if (this.prefix === "activiti") {Modules.push(activitiModdleExtension);}return Modules;},moddleExtensions() {const Extensions = {};// 仅使用用户自定义模块if (this.onlyCustomizeModdle) {return this.moddleExtension || null;}// 插入用户自定义模块if (this.moddleExtension) {for (let key in this.moddleExtension) {Extensions[key] = this.moddleExtension[key];}}// 根据需要的 "流程类型" 设置 对应的解析文件if (this.prefix === "activiti") {Extensions.activiti = activitiModdleDescriptor;}if (this.prefix === "flowable") {Extensions.flowable = flowableModdleDescriptor;}if (this.prefix === "camunda") {Extensions.camunda = camundaModdleDescriptor;}return Extensions;}},mounted() {this.initBpmnModeler();this.createNewDiagram(this.modelValue);// this.$once("hook:beforeUnmount", () => {//   if (this.bpmnModeler) this.bpmnModeler.destroy();//   this.$emit("destroy", this.bpmnModeler);//   this.bpmnModeler = null;// });},beforeUnmount() {if (this.bpmnModeler) this.bpmnModeler.destroy();this.$emit("destroy", this.bpmnModeler);this.bpmnModeler = null;},methods: {onSave () {return new Promise((resolve, reject) => {if (this.bpmnModeler == null) {reject();}this.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {this.$emit('save', xml);resolve(xml);});})},initBpmnModeler() {if (this.bpmnModeler) return;this.bpmnModeler = new BpmnModeler({container: this.$refs["bpmn-canvas"],keyboard: this.keyboard ? { bindTo: document } : null,additionalModules: this.additionalModules,moddleExtensions: this.moddleExtensions,...this.options});this.$emit("init-finished", this.bpmnModeler);this.initModelListeners();},initModelListeners() {const EventBus = this.bpmnModeler.get("eventBus");const that = this;// 注册需要的监听事件, 将. 替换为 - , 避免解析异常this.events.forEach(event => {EventBus.on(event, function(eventObj) {let eventName = event.replace(/\./g, "-");let element = eventObj ? eventObj.element : null;that.$emit(eventName, element, eventObj);});});// 监听图形改变返回xmlEventBus.on("commandStack.changed", async event => {try {this.recoverable = this.bpmnModeler.get("commandStack").canRedo();this.revocable = this.bpmnModeler.get("commandStack").canUndo();let { xml } = await this.bpmnModeler.saveXML({ format: true });this.$emit("commandStack-changed", event);this.$emit('update:modelValue', xml);this.$emit("change", xml);} catch (e) {console.error(`[Process Designer Warn]: ${e.message || e}`);}});// 监听视图缩放变化this.bpmnModeler.on("canvas.viewbox.changed", ({ viewbox }) => {this.$emit("canvas-viewbox-changed", { viewbox });const { scale } = viewbox;this.defaultZoom = Math.floor(scale * 100) / 100;});},/* 创建新的流程图 */async createNewDiagram(xml) {// 将字符串转换成图显示出来let newId = this.processId || `Process_${new Date().getTime()}`;let newName = this.processName || `业务流程_${new Date().getTime()}`;let xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix);try {let { warnings } = await this.bpmnModeler.importXML(xmlString);if (warnings && warnings.length) {warnings.forEach(warn => console.warn(warn));}} catch (e) {console.error(`[Process Designer Warn]: ${e?.message || e}`);}},// 下载流程图到本地/*** @param {string} type* @param {*} name*/async downloadProcess(type, name) {try {const _this = this;// 按需要类型创建文件并下载if (type === "xml" || type === "bpmn") {const { err, xml } = await this.bpmnModeler.saveXML();// 读取异常时抛出异常if (err) {console.error(`[Process Designer Warn ]: ${err.message || err}`);}let { href, filename } = _this.setEncoded(type.toUpperCase(), name, xml);downloadFunc(href, filename);} else {const { err, svg } = await this.bpmnModeler.saveSVG();// 读取异常时抛出异常if (err) {return console.error(err);}let { href, filename } = _this.setEncoded("SVG", name, svg);downloadFunc(href, filename);}} catch (e) {console.error(`[Process Designer Warn ]: ${e.message || e}`);}// 文件下载方法function downloadFunc(href, filename) {if (href && filename) {let a = document.createElement("a");a.download = filename; //指定下载的文件名a.href = href; //  URL对象a.click(); // 模拟点击URL.revokeObjectURL(a.href); // 释放URL 对象}}},// 根据所需类型进行转码并返回下载地址setEncoded(type, filename = "diagram", data) {const encodedData = encodeURIComponent(data);return {filename: `${filename}.${type}`,href: `data:application/${type === "svg" ? "text/xml" : "bpmn20-xml"};charset=UTF-8,${encodedData}`,data: data};},// 加载本地文件importLocalFile() {const that = this;const file = this.$refs.refFile.files[0];const reader = new FileReader();reader.readAsText(file);reader.onload = function() {let xmlStr = this.result;that.createNewDiagram(xmlStr);};},/* ------------------------------------------------ refs methods ------------------------------------------------------ */downloadProcessAsXml() {this.downloadProcess("xml");},downloadProcessAsBpmn() {this.downloadProcess("bpmn");},downloadProcessAsSvg() {this.downloadProcess("svg");},processSimulation() {this.simulationStatus = !this.simulationStatus;this.simulation && this.bpmnModeler.get("toggleMode").toggleMode();},processRedo() {this.bpmnModeler.get("commandStack").redo();},processUndo() {this.bpmnModeler.get("commandStack").undo();},processZoomIn(zoomStep = 0.1) {let newZoom = Math.floor(this.defaultZoom * 100 + zoomStep * 100) / 100;if (newZoom > 4) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");}this.defaultZoom = newZoom;this.bpmnModeler.get("canvas").zoom(this.defaultZoom);},processZoomOut(zoomStep = 0.1) {let newZoom = Math.floor(this.defaultZoom * 100 - zoomStep * 100) / 100;if (newZoom < 0.2) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");}this.defaultZoom = newZoom;this.bpmnModeler.get("canvas").zoom(this.defaultZoom);},processZoomTo(newZoom = 1) {if (newZoom < 0.2) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");}if (newZoom > 4) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");}this.defaultZoom = newZoom;this.bpmnModeler.get("canvas").zoom(newZoom);},processReZoom() {this.defaultZoom = 1;this.bpmnModeler.get("canvas").zoom("fit-viewport", "auto");},processRestart() {this.recoverable = false;this.revocable = false;this.createNewDiagram(null);},elementsAlign(align) {const Align = this.bpmnModeler.get("alignElements");const Selection = this.bpmnModeler.get("selection");const SelectedElements = Selection.get();if (!SelectedElements || SelectedElements.length <= 1) {this.$message.warning("请按住 Ctrl 键选择多个元素对齐");return;}this.$confirm("自动对齐可能造成图形变形,是否继续?", "警告", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(() => Align.trigger(SelectedElements, align));},/*-----------------------------    方法结束     ---------------------------------*/previewProcessXML() {this.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {this.previewResult = xml;this.previewType = 'xml';//this.cmOptions.mode = 'xml'this.previewModelVisible = true;});},previewProcessJson() {this.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {this.previewResult = convert.xml2json(xml, { spaces: 2 });this.previewType = "json";this.previewModelVisible = true;});}}
};
</script>

2、修改成vue3后的代码如下:

<template><div class="my-process-designer"><div class="my-process-designer__header"><slot name="control-header"></slot><template v-if="!$slots['control-header']"><el-button-group key="file-control"><el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-edit-outline" @click="onSave">保存流程</el-button><el-button :size="headerButtonSize" :type="headerButtonType" :icon="FolderOpened" @click="refFile.click()">打开文件</el-button><el-tooltip effect="light"><template #content><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsXml()">下载为XML文件</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsSvg()">下载为SVG文件</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="downloadProcessAsBpmn()">下载为BPMN文件</el-button></template><el-button :size="headerButtonSize" :type="headerButtonType" :icon="Download">下载文件</el-button></el-tooltip><el-tooltip effect="light"><template #content><el-button :size="headerButtonSize" type="primary" @click="previewProcessXML">预览XML</el-button><br /><el-button :size="headerButtonSize" type="primary" @click="previewProcessJson">预览JSON</el-button></template><el-button :size="headerButtonSize" :type="headerButtonType" :icon="View">预览</el-button></el-tooltip><el-tooltip v-if="simulation" effect="light" :content="simulationStatus ? '退出模拟' : '开启模拟'"><el-button :size="headerButtonSize" :type="headerButtonType" :icon="Cpu" @click="processSimulation">模拟</el-button></el-tooltip></el-button-group><el-button-group key="align-control"><el-tooltip effect="light" content="向左对齐"><el-button :size="headerButtonSize" class="align align-left" :icon="Histogram" @click="elementsAlign('left')" /></el-tooltip><el-tooltip effect="light" content="向右对齐"><el-button :size="headerButtonSize" class="align align-right" :icon="Histogram" @click="elementsAlign('right')" /></el-tooltip><el-tooltip effect="light" content="向上对齐"><el-button :size="headerButtonSize" class="align align-top" :icon="Histogram" @click="elementsAlign('top')" /></el-tooltip><el-tooltip effect="light" content="向下对齐"><el-button :size="headerButtonSize" class="align align-bottom" :icon="Histogram" @click="elementsAlign('bottom')" /></el-tooltip><el-tooltip effect="light" content="水平居中"><el-button :size="headerButtonSize" class="align align-center" :icon="Histogram" @click="elementsAlign('center')" /></el-tooltip><el-tooltip effect="light" content="垂直居中"><el-button :size="headerButtonSize" class="align align-middle" :icon="Histogram" @click="elementsAlign('middle')" /></el-tooltip></el-button-group><el-button-group key="scale-control"><el-tooltip effect="light" content="缩小视图"><el-button :size="headerButtonSize" :disabled="defaultZoom < 0.2" :icon="ZoomOut" @click="processZoomOut()" /></el-tooltip><el-button :size="headerButtonSize">{{ Math.floor(defaultZoom * 10 * 10) + "%" }}</el-button><el-tooltip effect="light" content="放大视图"><el-button :size="headerButtonSize" :disabled="defaultZoom > 4" :icon="ZoomIn" @click="processZoomIn()" /></el-tooltip><el-tooltip effect="light" content="重置视图并居中"><el-button :size="headerButtonSize" :icon="ScaleToOriginal" @click="processReZoom()" /></el-tooltip></el-button-group><el-button-group key="stack-control"><el-tooltip effect="light" content="撤销"><el-button :size="headerButtonSize" :disabled="!revocable" :icon="RefreshLeft" @click="processUndo()" /></el-tooltip><el-tooltip effect="light" content="恢复"><el-button :size="headerButtonSize" :disabled="!recoverable" :icon="RefreshRight" @click="processRedo()" /></el-tooltip><el-tooltip effect="light" content="重新绘制"><el-button :size="headerButtonSize" :icon="Refresh" @click="processRestart" /></el-tooltip></el-button-group></template><!-- 用于打开本地文件--><input type="file" id="files" ref="refFile" style="display: none" accept=".xml, .bpmn" @change="importLocalFile" /></div><div class="my-process-designer__container"><div class="my-process-designer__canvas" id = "bpmnCanvas" ref="bpmnCanvas"></div></div><el-dialog title="预览" width="60%" v-model="previewModelVisible" append-to-body destroy-on-close><highlightjs :language="previewType" :code="previewResult" style="height: 80vh" /></el-dialog><!--<el-dialog :title="`预览${previewType}`" width="60%" v-model="previewModelVisible" append-to-body destroy-on-close><Codemirrorv-model:value="previewResult":options="cmOptions"border:height="700"/></el-dialog>--></div>
</template><script lang="ts" setup>
import { Histogram, Cpu, Refresh, RefreshLeft, RefreshRight, ZoomOut, ZoomIn, View, Download, FolderOpened, ScaleToOriginal } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import BpmnModeler from "bpmn-js/lib/Modeler";
import DefaultEmptyXML from "./plugins/defaultEmpty";
// 翻译方法
import customTranslate from "./plugins/translate/customTranslate";
import translationsCN from "./plugins/translate/zh";
// 模拟流转流程
import tokenSimulation from "bpmn-js-token-simulation";
// 标签解析构建器
// import bpmnPropertiesProvider from "bpmn-js-properties-panel/lib/provider/bpmn";
// 标签解析 Moddle
import camundaModdleDescriptor from './plugins/descriptor/camundaDescriptor.json';
import activitiModdleDescriptor from './plugins/descriptor/activitiDescriptor.json';
import flowableModdleDescriptor from './plugins/descriptor/flowableDescriptor.json';
// 标签解析 Extension
import camundaModdleExtension from './plugins/extension-moddle/camunda';
import activitiModdleExtension from './plugins/extension-moddle/activiti';
import flowableModdleExtension from './plugins/extension-moddle/flowable';
// 引入json转换与高亮
// import X2JS from "x2js";
import convert from "xml-js";import Codemirror from 'codemirror-editor-vue3';
import 'codemirror/theme/monokai.css'
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/xml/xml.js';defineOptions({ name: 'MyProcessDesigner' })const refFile = ref()
const emit = defineEmits(['destroy','init-finished','commandStack-changed','update:modelValue','change','canvas-viewbox-changed','element-click'
])const props = defineProps({modelValue: String, // xml 字符串processId: String, // 流程 key 标识processName: String, // 流程 name 名字formId: Number, // 流程 form 表单编号translations: {// 自定义的翻译文件type: Object,default: () => {}},options: {type: Object,default: () => ({})}, // 自定义的翻译文件additionalModel: [Object, Array], // 自定义modelmoddleExtension: {// 自定义moddletype: Object,default: () => {}},onlyCustomizeAddi: {type: Boolean,default: false},onlyCustomizeModdle: {type: Boolean,default: false},simulation: {type: Boolean,default: true},keyboard: {type: Boolean,default: true},prefix: {type: String,default: 'flowable'},events: {type: Array,default: () => ['element.click']},headerButtonSize: {type: String,default: 'small',validator: (value: string) => ['default', 'medium', 'small', 'mini'].indexOf(value) !== -1},headerButtonType: {type: String,default: 'primary',validator: (value: string) =>['default', 'primary', 'success', 'warning', 'danger', 'info'].indexOf(value) !== -1}
})let bpmnModeler: any = null
const defaultZoom = ref(1)
const previewModelVisible = ref(false)
const simulationStatus = ref(false)
const previewResult = ref('')
const previewType = ref('xml')
const recoverable = ref(false)
const revocable = ref(false)const cmOptions = ref({mode: 'xml', // 语言模式theme: 'monokai', // 主题lineNumbers: true, // 显示行号smartIndent: true, // 智能缩进readOnly: true,indentUnit: 2, // 智能缩进单位为4个空格长度foldGutter: true, // 启用行槽中的代码折叠styleActiveLine: true // 显示选中行的样式
})const additionalModules = computed(() => {const Modules: any[] = []// 仅保留用户自定义扩展模块if (props.onlyCustomizeAddi) {if (Object.prototype.toString.call(props.additionalModel) == '[object Array]') {return props.additionalModel || []}return [props.additionalModel]}// 插入用户自定义扩展模块if (Object.prototype.toString.call(props.additionalModel) == '[object Array]') {Modules.push(...(props.additionalModel as any[]))} else {props.additionalModel && Modules.push(props.additionalModel)}// 翻译模块const TranslateModule = {translate: ['value', customTranslate(props.translations || translationsCN)]}Modules.push(TranslateModule)// 模拟流转模块if (props.simulation) {Modules.push(tokenSimulation)}// 根据需要的流程类型设置扩展元素构建模块// if (this.prefix === "bpmn") {//   Modules.push(bpmnModdleExtension);// }if (props.prefix === 'camunda') {Modules.push(camundaModdleExtension)}if (props.prefix === 'flowable') {Modules.push(flowableModdleExtension)}if (props.prefix === 'activiti') {Modules.push(activitiModdleExtension)}return Modules
})const moddleExtensions = computed(() => {const Extensions: any = {}// 仅使用用户自定义模块if (props.onlyCustomizeModdle) {return props.moddleExtension || null}// 插入用户自定义模块if (props.moddleExtension) {for (let key in props.moddleExtension) {Extensions[key] = props.moddleExtension[key]}}// 根据需要的 "流程类型" 设置 对应的解析文件if (props.prefix === 'activiti') {Extensions.activiti = activitiModdleDescriptor}if (props.prefix === 'flowable') {Extensions.flowable = flowableModdleDescriptor}if (props.prefix === 'camunda') {Extensions.camunda = camundaModdleDescriptor}return Extensions
})const onSave = async () => {return new Promise((resolve, reject) => {if (bpmnModeler == null) {reject();}bpmnModeler.saveXML({ format: true }).then(({ xml }) => {// 触发 save 事件emit('save', xml)resolve(xml);});})
}const initBpmnModeler = () => {if (bpmnModeler) returnlet container = document.getElementById('bpmnCanvas')bpmnModeler = new BpmnModeler({container: container,keyboard: props.keyboard ? { bindTo: document } : null,additionalModules: additionalModules.value,moddleExtensions: moddleExtensions.value,...props.options})console.log("initBpmnModeler bpmnModeler",bpmnModeler)emit('init-finished', bpmnModeler)initModelListeners()
}const initModelListeners = () => {const EventBus = bpmnModeler.get('eventBus')// 注册需要的监听事件, 将. 替换为 - , 避免解析异常props.events.forEach((event: any) => {EventBus.on(event, function (eventObj) {let eventName = event.replace(/\./g, '-')let element = eventObj ? eventObj.element : nullemit('element-click', element, eventObj)// emit(eventName, element, eventObj)})})// 监听图形改变返回xmlEventBus.on('commandStack.changed', async (event) => {try {recoverable.value = bpmnModeler.get('commandStack').canRedo()revocable.value = bpmnModeler.get('commandStack').canUndo()let { xml } = await bpmnModeler.saveXML({ format: true })emit('commandStack-changed', event)emit('update:modelValue', xml)emit('change', xml)} catch (e: any) {console.error(`[Process Designer Warn]: ${e.message || e}`)}})// 监听视图缩放变化bpmnModeler.on('canvas.viewbox.changed', ({ viewbox }) => {emit('canvas-viewbox-changed', { viewbox })const { scale } = viewboxdefaultZoom.value = Math.floor(scale * 100) / 100})
}
/* 创建新的流程图 */
const createNewDiagram = async (xml) => {// 将字符串转换成图显示出来let newId = props.processId || `Process_${new Date().getTime()}`let newName = props.processName || `业务流程_${new Date().getTime()}`let xmlString = xml || DefaultEmptyXML(newId, newName, props.prefix)try {let { warnings } = await bpmnModeler.importXML(xmlString)if (warnings && warnings.length) {warnings.forEach((warn) => console.warn(warn))}} catch (e: any) {console.error(`[Process Designer Warn]: ${e.message || e}`)}
}// 下载流程图到本地/*** @param {string} type* @param {*} name*/
const downloadProcess = async (type, name) => {try {// 按需要类型创建文件并下载if (type === 'xml' || type === 'bpmn') {const { err, xml } = await bpmnModeler.saveXML()// 读取异常时抛出异常if (err) {console.error(`[Process Designer Warn ]: ${err.message || err}`)}let { href, filename } = setEncoded(type.toUpperCase(), name, xml)downloadFunc(href, filename)} else {const { err, svg } = await bpmnModeler.saveSVG()// 读取异常时抛出异常if (err) {return console.error(err)}let { href, filename } = setEncoded('SVG', name, svg)downloadFunc(href, filename)}} catch (e: any) {console.error(`[Process Designer Warn ]: ${e.message || e}`)}// 文件下载方法function downloadFunc(href, filename) {if (href && filename) {let a = document.createElement('a')a.download = filename //指定下载的文件名a.href = href //  URL对象a.click() // 模拟点击URL.revokeObjectURL(a.href) // 释放URL 对象}}
}
// 根据所需类型进行转码并返回下载地址
const setEncoded = (type, filename = 'diagram', data) => {const encodedData = encodeURIComponent(data)return {filename: `${filename}.${type}`,href: `data:application/${type === "svg" ? "text/xml" : "bpmn20-xml"};charset=UTF-8,${encodedData}`,data: data}
}// 加载本地文件
const importLocalFile = () => {const file = refFile.value.files[0]const reader = new FileReader()reader.readAsText(file)reader.onload = function () {let xmlStr = this.resultcreateNewDiagram(xmlStr)}
}
/* ------------------------------------------------ refs methods ------------------------------------------------------ */
const downloadProcessAsXml = () => {downloadProcess('xml')
}
const downloadProcessAsBpmn = () => {downloadProcess('bpmn')
}
const downloadProcessAsSvg = () => {downloadProcess('svg')
}
const processSimulation = () => {simulationStatus.value = !simulationStatus.valueprops.simulation && bpmnModeler.get('toggleMode').toggleMode()
}
const processRedo = () => {bpmnModeler.get('commandStack').redo()
}
const processUndo = () => {bpmnModeler.get('commandStack').undo()
}
const processZoomIn = (zoomStep = 0.1) => {let newZoom = Math.floor(defaultZoom.value * 100 + zoomStep * 100) / 100if (newZoom > 4) {throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4')}defaultZoom.value = newZoombpmnModeler.get('canvas').zoom(defaultZoom.value)
}
const processZoomOut = (zoomStep = 0.1) => {let newZoom = Math.floor(defaultZoom.value * 100 - zoomStep * 100) / 100if (newZoom < 0.2) {throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2')}defaultZoom.value = newZoombpmnModeler.get('canvas').zoom(defaultZoom.value)
}
const processZoomTo = (newZoom = 1) => {if (newZoom < 0.2) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");}if (newZoom > 4) {throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");}defaultZoom.value = newZoom;bpmnModeler.get("canvas").zoom(newZoom);
}const processReZoom = () => {defaultZoom.value = 1bpmnModeler.get('canvas').zoom('fit-viewport', 'auto')
}const processRestart = () => {recoverable.value = falserevocable.value = falsecreateNewDiagram(null)
}
const elementsAlign = (align) => {const Align = bpmnModeler.get('alignElements')const Selection = bpmnModeler.get('selection')const SelectedElements = Selection.get()if (!SelectedElements || SelectedElements.length <= 1) {ElMessage.warning('请按住 Shift 键选择多个元素对齐')return}ElMessageBox.confirm('自动对齐可能造成图形变形,是否继续?', '警告', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {Align.trigger(SelectedElements, align)})
}
/*-----------------------------    方法结束     ---------------------------------*/
const previewProcessXML = () => {bpmnModeler.saveXML({ format: true }).then(({ xml }) => {previewResult.value = xmlpreviewType.value = 'xml'//cmOptions.value['mode'] = 'xml'previewModelVisible.value = true})
}
const previewProcessJson = () => {bpmnModeler.saveXML({ format: true }).then(({ xml }) => {previewResult.value = convert.xml2json(xml, { spaces: 2 });previewType.value = "json";previewModelVisible.value = true;})
}onMounted(() => {initBpmnModeler()createNewDiagram(props.modelValue)
})onBeforeUnmount(() => {if (bpmnModeler) bpmnModeler.destroy()emit('destroy', bpmnModeler)bpmnModeler = null
})
</script>

3、效果图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/791900.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql故障排查

MySQL是目前企业最常见的数据库之一日常维护管理的过程中&#xff0c;会遇到很多故障汇总了常见的故障&#xff0c;MySQL默认配置无法满足高性能要求 一 MySQL逻辑架构图 客户端和连接服务核心服务功能存储擎层数据存储层 二 MySQL单实例常见故障 故障1 ERROR 2002 (HY000)…

深入理解npm常用命令

npm&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;用于管理 Node.js 应用程序的依赖包。除了安装、更新和卸载依赖包外&#xff0c;npm 还提供了许多其他功能&#xff0c;如初始化项目、运行脚本、查看依赖树等。本文将详细介绍一些常用的 …

RabbitMQ3.x之六_RabbitMQ使用场景

RabbitMQ3.x之六_RabbitMQ使用场景 文章目录 RabbitMQ3.x之六_RabbitMQ使用场景1. 为什么选择 RabbitMQ&#xff1f;1. 可互操作2. 灵活3. 可靠 2. 常见用户案例1. 服务解耦2. 远程过程调用3. 流处理4. 物联网 1. 为什么选择 RabbitMQ&#xff1f; RabbitMQ 是一个可靠且成熟的…

linux------jekins构建cicd

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;linux &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#…

vue3+threejs新手从零开发卡牌游戏(二十四):添加p2战斗逻辑

用代码模拟p2战斗逻辑&#xff0c;按流程进行步骤拆分&#xff1a; 1.p2抽卡 2.p2召唤怪兽上场 3.p2战斗 其中战斗部分分为几种情况&#xff1a; 情况一&#xff1a;p2场上卡牌由大到小进行排序&#xff0c;按序轮询可以攻击的卡牌&#xff0c;然后攻击p1场上卡牌由大到小…

第19次修改了可删除可持久保存的前端html备忘录:换了一个特别的倒计时时钟

第19次修改了可删除可持久保存的前端html备忘录:换了一个特别的倒计时时钟 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><met…

android framework 学习笔记(1)

学习资料&#xff1a;《Android Framework 开发揭秘》_哔哩哔哩_bilibili 什么是android framework 看图说话&#xff0c;android框架从上至下分为&#xff1a; 应用层(Application)&#xff0c;Java framework(Application Framework),Native framework. 包括Libraries 和 A…

数据透视:将三特征数据集转为矩阵

本文记录利用 wps的excel软件 将包含三个变量的数据集转换成矩阵的表达形式。 1.三特征数据集 三特征数据集/三元数据集&#xff1a;原始数据集的一般表达形式。每一行代表一个样本&#xff0c;每一列代表一个变量&#xff0c;共有3个变量。 2.数据透视表 设置3个变量的行、列和…

CSS3新增的语法(四)

CSS3新增的语法&#xff08;四&#xff09;【布局】 14. 多列布局15.伸缩盒模型1. 伸缩盒模型简介2. 伸缩容器、伸缩项目3. 主轴与侧轴4. 主轴方向5. 主轴换行方式6. flex-flow7. 主轴对齐方式8. 侧轴对齐方式8.1 一行的情况8.2 多行的情况 9.flex 实现水平垂直居中10. 伸缩性1…

【leetcode C++】滑动窗口

1. LCR 008. 长度最小的子数组 题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 题目…

“梦该醒了,少年”

顺序表 1、数据结构相关概念2、顺序表2.1、顺序表的概念及结构2.2、顺序表分类2.3、动态顺序表的实现 3、ps:源码 1、数据结构相关概念 数据结构是由“数据”和“结构”两词组合⽽来。 什么是数据&#xff1f; 常⻅的数值1、2、3、4…、教务系统⾥保存的⽤⼾信息&#xff08…

将 Elasticsearch 向量数据库引入到数据上的 Azure OpenAI 服务(预览)

作者&#xff1a;来自 Elastic Aditya Tripathi Microsoft 和 Elastic 很高兴地宣布&#xff0c;全球下载次数最多的向量数据库 Elasticsearch 是公共预览版中 Azure OpenAI Service On Your Data 官方支持的向量存储和检索增强搜索技术。 这项突破性的功能使你能够利用 GPT-4 …

docker-compose运行springinitializr用来创建springboot2

前言 spring initializr官方的地址是: https://start.spring.io/ &#xff0c;这是一个用来创建springboot脚手架的一个工具&#xff0c;但是目前这个工具已经更新到springboot3&#xff0c;而我还没学springboot3&#xff0c;目前还想继续创建springboot2&#xff0c;我就想能…

vue处理后端返回的日志

vue处理后端返回的日志&#xff0c;并保持日志内容最新&#xff08;滚动到最新内容&#xff09; 1、后端返回的日志格式如下所示&#xff0c;该如何处理成正常的文本换行 2、在获取日志的接口中做如下处理&#xff0c;把返回的/n替换成换行标签&#xff0c;并根据任务状态判断…

在Windows的Docker上部署Mysql服务

在我们做一些和数据库相关的测试时&#xff0c;往往需要快速部署一个数据库作为数据源。如果开发环境是Windows&#xff0c;且开发的代码不依赖于系统&#xff0c;即不用在linux上做开发&#xff0c;则可以将全套环境都部署在Windows上。 本地安装数据库会污染操作系统环境&…

算法设计与分析实验报告python实现(串匹配问题、采用分治法求解最大连续子序列和问题、用分治策略求众数问题、最近点对问题)

一、 实验目的 1&#xff0e;加深学生对算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、串匹配问…

Vue2电商前台项目(一):项目前的初始化及搭建

一、项目初始化 创建项目&#xff1a;sudo vue create app 1.项目配置 &#xff08;1&#xff09;浏览器自动打开 在package.json文件中&#xff0c;serve后面加上 --open "scripts": {"serve": "vue-cli-service serve --open","buil…

我与C++的爱恋:类与对象(一)

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 ​C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&…

Tomcat安装部署及JavaEE项目创建

一.Tomcat下载 官网链接 选择自己需要的版本&#xff08;本次采用Tomcat10&#xff09;下载 二.文件结构 解压下载的文件&#xff0c;其主要文件目录如下&#xff1a; 三.启动Tomcat 找到bin目录下的startup.bat文件&#xff0c;双击运行 启动后出现弹窗&#xff0…

【数据结构】初识数据结构与复杂度总结

前言 C语言这块算是总结完了&#xff0c;那从本篇开始就是步入一个新的大章——数据结构&#xff0c;这篇我们先来认识一下数据结构有关知识&#xff0c;以及复杂度的相关知识 个人主页&#xff1a;小张同学zkf 若有问题 评论区见 感兴趣就关注一下吧 目录 1.什么是数据结构 2.…