mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	完善 bpmnProcessDesigner 流程设计器的使用,基本可用了!
This commit is contained in:
		| @@ -43,5 +43,10 @@ export function getFormPage(query) { | ||||
|   }) | ||||
| } | ||||
|  | ||||
| export class exportFormExcel { | ||||
| // 获得动态表单的精简列表 | ||||
| export function getSimpleForms() { | ||||
|   return request({ | ||||
|     url: '/bpm/form/list-all-simple', | ||||
|     method: 'get' | ||||
|   }) | ||||
| } | ||||
|   | ||||
| @@ -5,4 +5,17 @@ github 地址:https://github.com/JakHuang/form-generator | ||||
| * generator | ||||
| * parser | ||||
| * render | ||||
| * tinymce | ||||
| * tinymce | ||||
|  | ||||
| ## bpmn-process-designer | ||||
|  | ||||
| github 地址:https://github.com/miyuesc/bpmn-process-designer | ||||
|  | ||||
| * bpmnProcessDesigner | ||||
|  | ||||
| TODO 目前存在的问题,如果选择 activiti 类型时,因为不支持内置表单的设计,所以会报 Error: unknown type activiti:FormData 错误。具体可见 https://github.com/miyuesc/bpmn-process-designer/issues/16 。 | ||||
|  | ||||
| 另外几个流程设计器的选型: | ||||
|  | ||||
| * https://gitee.com/jimlow/vue-bpmn 相比差一些,已经停止维护,不算推荐。 | ||||
| * https://github.com/GoldSubmarine/workflow-bpmn-modeler 仅支持 flowable 流程引擎。如果只考虑 flowable 的话,也是非常不错的选择。 | ||||
| @@ -4,7 +4,7 @@ | ||||
|       <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-folder-opened" @click="$refs.refFile.click()">打开文件</el-button> | ||||
|           <el-button :size="headerButtonSize" icon="el-icon-folder-opened" @click="$refs.refFile.click()">打开文件</el-button> | ||||
|           <el-tooltip effect="light"> | ||||
|             <div slot="content"> | ||||
|               <el-button :size="headerButtonSize" type="text" @click="downloadProcessAsXml()">下载为XML文件</el-button> | ||||
| @@ -13,7 +13,7 @@ | ||||
|               <br /> | ||||
|               <el-button :size="headerButtonSize" type="text" @click="downloadProcessAsBpmn()">下载为BPMN文件</el-button> | ||||
|             </div> | ||||
|             <el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-download">下载文件</el-button> | ||||
|             <el-button :size="headerButtonSize" icon="el-icon-download">下载文件</el-button> | ||||
|           </el-tooltip> | ||||
|           <el-tooltip effect="light"> | ||||
|             <div slot="content"> | ||||
| @@ -21,10 +21,10 @@ | ||||
|               <br /> | ||||
|               <el-button :size="headerButtonSize" type="text" @click="previewProcessJson">预览JSON</el-button> | ||||
|             </div> | ||||
|             <el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-view">预览</el-button> | ||||
|             <el-button :size="headerButtonSize" icon="el-icon-view">预览</el-button> | ||||
|           </el-tooltip> | ||||
|           <el-tooltip v-if="simulation" effect="light" :content="this.simulationStatus ? '退出模拟' : '开启模拟'"> | ||||
|             <el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-cpu" @click="processSimulation"> | ||||
|             <el-button :size="headerButtonSize" icon="el-icon-cpu" @click="processSimulation"> | ||||
|               模拟 | ||||
|             </el-button> | ||||
|           </el-tooltip> | ||||
| @@ -72,6 +72,7 @@ | ||||
|             <el-button :size="headerButtonSize" icon="el-icon-refresh" @click="processRestart" /> | ||||
|           </el-tooltip> | ||||
|         </el-button-group> | ||||
|         <el-button :size="headerButtonSize" :type="headerButtonType" icon="el-icon-plus" @click="processSave">保存模型</el-button> | ||||
|       </template> | ||||
|       <!-- 用于打开本地文件--> | ||||
|       <input type="file" id="files" ref="refFile" style="display: none" accept=".xml, .bpmn" @change="importLocalFile" /> | ||||
| @@ -111,8 +112,9 @@ export default { | ||||
|   componentName: "MyProcessDesigner", | ||||
|   props: { | ||||
|     value: String, // xml 字符串 | ||||
|     processId: String, | ||||
|     processName: String, | ||||
|     processId: String, // 流程 key 标识 | ||||
|     processName: String, // 流程 name 名字 | ||||
|     formId: Number, // 流程 form 表单编号 | ||||
|     translations: Object, // 自定义的翻译文件 | ||||
|     additionalModel: [Object, Array], // 自定义model | ||||
|     moddleExtension: Object, // 自定义moddle | ||||
| @@ -244,6 +246,11 @@ export default { | ||||
|       this.bpmnModeler = null; | ||||
|     }); | ||||
|   }, | ||||
|   watch: { | ||||
|     value: function (newValue) { // 在 xmlString 发生变化时,重新创建,从而绘制流程图 | ||||
|       this.createNewDiagram(newValue); | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     initBpmnModeler() { | ||||
|       if (this.bpmnModeler) return; | ||||
| @@ -445,6 +452,17 @@ export default { | ||||
|         this.previewType = "json"; | ||||
|         this.previewModelVisible = true; | ||||
|       }); | ||||
|     }, | ||||
|     /* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */ | ||||
|     async processSave() { | ||||
|       const { err, xml } = await this.bpmnModeler.saveXML(); | ||||
|       // 读取异常时抛出异常 | ||||
|       if (err) { | ||||
|         this.msgError('保存模型失败,请重试!') | ||||
|         return | ||||
|       } | ||||
|       // 触发 save 事件 | ||||
|       this.$emit('save', xml) | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -3,7 +3,8 @@ | ||||
|     <el-collapse v-model="activeTab"> | ||||
|       <el-collapse-item name="base"> | ||||
|         <div slot="title" class="panel-tab__title"><i class="el-icon-info"></i>常规</div> | ||||
|         <element-base-info :id-edit-disabled="idEditDisabled" :business-object="elementBusinessObject" :type="elementType" /> | ||||
|         <element-base-info :id-edit-disabled="idEditDisabled" :business-object="elementBusinessObject" :type="elementType" | ||||
|                            :model="model" /> | ||||
|       </el-collapse-item> | ||||
|       <el-collapse-item name="condition" v-if="elementType === 'Process'" key="message"> | ||||
|         <div slot="title" class="panel-tab__title"><i class="el-icon-s-comment"></i>消息与信号</div> | ||||
| @@ -89,7 +90,8 @@ export default { | ||||
|     idEditDisabled: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     } | ||||
|     }, | ||||
|     model: Object, // 流程模型的数据 | ||||
|   }, | ||||
|   provide() { | ||||
|     return { | ||||
| @@ -159,6 +161,7 @@ export default { | ||||
|     // 初始化数据 | ||||
|     initFormOnChanged(element) { | ||||
|       let activatedElement = element; | ||||
|       // debugger | ||||
|       if (!activatedElement) { | ||||
|         activatedElement = | ||||
|           window.bpmnInstances.elementRegistry.find(el => el.type === "bpmn:Process") ?? | ||||
|   | ||||
| @@ -1,43 +1,53 @@ | ||||
| <template> | ||||
|   <div class="panel-tab__content"> | ||||
|     <el-form size="mini" label-width="90px" @submit.native.prevent> | ||||
|       <el-form-item label="ID"> | ||||
|         <el-input | ||||
|           v-model="elementBaseInfo.id" | ||||
|           :disabled="idEditDisabled || elementBaseInfo.$type === 'bpmn:Process'" | ||||
|           clearable | ||||
|           @change="updateBaseInfo('id')" | ||||
|         /> | ||||
|     <el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent> | ||||
|       <el-form-item label="流程标识" prop="key"> | ||||
|         <el-input v-model="model.key" placeholder="请输入流标标识" | ||||
|                   :disabled="model.id !== undefined && model.id.length > 0"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="名称"> | ||||
|         <el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" /> | ||||
|       <el-form-item label="流程名称" prop="name"> | ||||
|         <el-input v-model="model.name" placeholder="请输入流程名称" clearable /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="流程分类" prop="category"> | ||||
|         <el-select v-model="model.category" placeholder="请选择流程分类" clearable style="width: 100%"> | ||||
|           <el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="流程表单" prop="formId"> | ||||
|         <el-select v-model="model.formId" placeholder="请选择流程表单,非必选哟!" clearable style="width: 100%"> | ||||
|           <el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="流程描述" prop="description"> | ||||
|         <el-input type="textarea" v-model="model.description" clearable /> | ||||
|       </el-form-item> | ||||
|       <!--流程的基础属性--> | ||||
|       <template v-if="elementBaseInfo.$type === 'bpmn:Process'"> | ||||
|         <el-form-item label="版本标签"> | ||||
|           <el-input v-model="elementBaseInfo.versionTag" clearable @change="updateBaseInfo('versionTag')" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="可执行"> | ||||
|           <el-switch v-model="elementBaseInfo.isExecutable" active-text="是" inactive-text="否" @change="updateBaseInfo('isExecutable')" /> | ||||
|         </el-form-item> | ||||
|       </template> | ||||
|     </el-form> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import {DICT_TYPE, getDictDatas} from "@/utils/dict"; | ||||
| import {getSimpleForms} from "@/api/bpm/form"; | ||||
| import {getModel} from "@/api/bpm/model"; | ||||
|  | ||||
| export default { | ||||
|   name: "ElementBaseInfo", | ||||
|   props: { | ||||
|     businessObject: Object, | ||||
|     type: String, | ||||
|     idEditDisabled: { | ||||
|       type: Boolean, | ||||
|       default: true | ||||
|     } | ||||
|     model: Object, // 流程模型的数据 | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       elementBaseInfo: {} | ||||
|       elementBaseInfo: {}, | ||||
|       // 流程表单的下拉框的数据 | ||||
|       forms: [], | ||||
|       // 流程模型的校验 | ||||
|       rules: { | ||||
|         key: [{ required: true, message: "流程标识不能为空", trigger: "blur" }], | ||||
|         name: [{ required: true, message: "流程名称不能为空", trigger: "blur" }], | ||||
|         category: [{ required: true, message: "流程分类不能为空", trigger: "blur" }], | ||||
|       }, | ||||
|       // 数据字典 | ||||
|       categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY), | ||||
|     }; | ||||
|   }, | ||||
|   watch: { | ||||
| @@ -50,12 +60,19 @@ export default { | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     // 获得流程表单的下拉框的数据 | ||||
|     getSimpleForms().then(response => { | ||||
|       this.forms = response.data | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     resetBaseInfo() { | ||||
|       this.bpmnElement = window?.bpmnInstances?.bpmnElement; | ||||
|       this.elementBaseInfo = JSON.parse(JSON.stringify(this.bpmnElement.businessObject)); | ||||
|     }, | ||||
|     updateBaseInfo(key) { | ||||
|       // 触发 elementBaseInfo 对应的字段 | ||||
|       const attrObj = Object.create(null); | ||||
|       attrObj[key] = this.elementBaseInfo[key]; | ||||
|       if (key === "id") { | ||||
|   | ||||
| @@ -76,11 +76,10 @@ Vue.component('RightToolbar', RightToolbar) | ||||
| Vue.use(permission) | ||||
| // Vue.use(hljs.vuePlugin); | ||||
|  | ||||
| // TODO 芋艿:bpmnProcessDesigner 引入 | ||||
| // bpmnProcessDesigner 需要引入 | ||||
| import MyPD from "@/components/bpmnProcessDesigner/package/index.js"; | ||||
| Vue.use(MyPD); | ||||
| import "@/components/bpmnProcessDesigner/package/theme/index.scss"; | ||||
| // TODO 芋艿:bpmnProcessDesigner 引入 | ||||
| import "bpmn-js/dist/assets/diagram-js.css"; | ||||
| import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css"; | ||||
| import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css"; | ||||
|   | ||||
| @@ -67,12 +67,6 @@ | ||||
|     <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | ||||
|                 @pagination="getList"/> | ||||
|  | ||||
|     <!-- 流程编辑器 --> | ||||
| <!--    <el-dialog class="bpmnclass dialogClass" :visible.sync="showBpmnOpen" :before-cancel="cancel" :fullscreen="true">--> | ||||
| <!--      <vue-bpmn v-if="showBpmnOpen" product="activiti" @processSave="processSave"--> | ||||
| <!--                :bpmnXml="bpmnXML" :bpmnData="bpmnData" @beforeClose="cancel" />--> | ||||
| <!--    </el-dialog>--> | ||||
|  | ||||
|     <!-- 流程表单配置详情 --> | ||||
|     <el-dialog title="表单详情" :visible.sync="detailOpen" width="50%" append-to-body> | ||||
|       <div class="test-form"> | ||||
| @@ -83,8 +77,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {deleteModel, deployModel, createModel, updateModel, getModelPage, getModel} from "@/api/bpm/model"; | ||||
| // import VueBpmn from "@/components/bpmn/VueBpmn"; | ||||
| import {deleteModel, deployModel, getModelPage} from "@/api/bpm/model"; | ||||
| import {DICT_TYPE, getDictDatas} from "@/utils/dict"; | ||||
| import {getForm} from "@/api/bpm/form"; | ||||
| import {decodeFields} from "@/utils/formGenerator"; | ||||
| @@ -93,8 +86,7 @@ import Parser from '@/components/parser/Parser' | ||||
| export default { | ||||
|   name: "model", | ||||
|   components: { | ||||
|     Parser, | ||||
|     // VueBpmn | ||||
|     Parser | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
| @@ -157,55 +149,22 @@ export default { | ||||
|       this.resetForm("queryForm"); | ||||
|       this.handleQuery(); | ||||
|     }, | ||||
|     processSave(data) { | ||||
|       // TODO 芋艿:临时写死的参数 | ||||
|       data.category = '1' | ||||
|       data.formId = 11 | ||||
|  | ||||
|       // 修改的提交 | ||||
|       if (data.id) { | ||||
|         updateModel(data).then(response => { | ||||
|           this.msgSuccess("修改成功"); | ||||
|           // 关闭弹窗,刷新列表 | ||||
|           this.showBpmnOpen = false | ||||
|           this.getList(); | ||||
|         }) | ||||
|         return | ||||
|       } | ||||
|       // 添加的提交 | ||||
|       createModel(data).then(response => { | ||||
|         this.bpmnData.id = response.data | ||||
|         this.msgSuccess("保存成功"); | ||||
|         // 关闭弹窗,刷新列表 | ||||
|         this.showBpmnOpen = false | ||||
|         this.getList(); | ||||
|       }) | ||||
|     }, | ||||
|     /** 新增按钮操作 */ | ||||
|     handleAdd() { | ||||
|       // 重置 Model 信息 | ||||
|       this.reset() | ||||
|       // 打开弹窗 | ||||
|       this.showBpmnOpen = true | ||||
|     }, | ||||
|     cancel() { | ||||
|       // 打开弹窗 | ||||
|       this.showBpmnOpen = false | ||||
|       // 重置 Model 信息 | ||||
|       this.reset() | ||||
|       // 刷新列表 | ||||
|       this.getList() | ||||
|       this.$router.push({ | ||||
|         path:"/bpm/manager/model/edit" | ||||
|       }); | ||||
|     }, | ||||
|     /** 修改按钮操作 */ | ||||
|     handleUpdate(row) { | ||||
|       // 重置 Model 信息 | ||||
|       this.reset() | ||||
|       // 获得 Model 信息 | ||||
|       getModel(row.id).then(response => { | ||||
|         this.bpmnXML = response.data.bpmnXml | ||||
|         this.bpmnData = response.data | ||||
|         // 打开弹窗 | ||||
|         this.showBpmnOpen = true | ||||
|       }) | ||||
|       this.$router.push({ | ||||
|         path:"/bpm/manager/model/edit", | ||||
|         query:{ | ||||
|           modelId: row.id | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     /** 删除按钮操作 */ | ||||
|     handleDelete(row) { | ||||
|       const that = this; | ||||
|       this.$confirm('是否删除该流程!!', "警告", { | ||||
| @@ -219,6 +178,7 @@ export default { | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     /** 部署按钮操作 */ | ||||
|     handleDeploy(row) { | ||||
|       const that = this; | ||||
|       this.$confirm('是否部署该流程!!', "提示", { | ||||
| @@ -248,19 +208,3 @@ export default { | ||||
|   } | ||||
| }; | ||||
| </script> | ||||
| <style> | ||||
| .el-dialog > .el-dialog__body{ | ||||
|   margin: 0; | ||||
|   border: 0; | ||||
| } | ||||
| .bpmn-viewer-header{ | ||||
|   background: white; | ||||
| } | ||||
| .v-modal{ | ||||
|   z-index: 2000!important; | ||||
| } | ||||
| .dialogClass{ | ||||
|   padding: 0  ; | ||||
| } | ||||
| </style> | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,14 @@ | ||||
| <template> | ||||
|   <div class="app-container"> | ||||
|  | ||||
|     <!-- 流程编辑器 --> | ||||
|     <!-- 流程设计器,负责绘制流程等 --> | ||||
|     <my-process-designer :key="`designer-${reloadIndex}`" v-model="xmlString" v-bind="controlForm" | ||||
|       keyboard ref="processDesigner" @init-finished="initModeler"/> | ||||
|     <!-- 右边工具栏 --> | ||||
|     <my-properties-panel :key="`penal-${reloadIndex}`" :bpmn-modeler="modeler" :prefix="controlForm.prefix" class="process-panel" /> | ||||
|       keyboard ref="processDesigner" @init-finished="initModeler" | ||||
|       @save="save"/> | ||||
|  | ||||
|     <!-- 流程属性器,负责编辑每个流程节点的属性 --> | ||||
|     <my-properties-panel :key="`penal-${reloadIndex}`" :bpmn-modeler="modeler" :prefix="controlForm.prefix" class="process-panel" | ||||
|       :model="model" /> | ||||
|  | ||||
|   </div> | ||||
| </template> | ||||
| @@ -18,6 +21,7 @@ import CustomContentPadProvider from "@/components/bpmnProcessDesigner/package/d | ||||
| import CustomPaletteProvider from "@/components/bpmnProcessDesigner/package/designer/plugins/palette"; | ||||
| // import xmlObj2json from "./utils/xml2json"; | ||||
| import MyProcessPalette from "@/components/bpmnProcessDesigner/package/palette/ProcessPalette"; | ||||
| import {createModel, getModel, updateModel} from "@/api/bpm/model"; | ||||
| // 自定义侧边栏 | ||||
| // import MyProcessPanel from "../package/process-panel/ProcessPanel"; | ||||
|  | ||||
| @@ -32,23 +36,34 @@ export default { | ||||
|       controlDrawerVisible: false, | ||||
|       translationsSelf: translations, | ||||
|       controlForm: { | ||||
|         processId: "", | ||||
|         processName: "", | ||||
|         simulation: true, | ||||
|         labelEditing: false, | ||||
|         labelVisible: false, | ||||
|         prefix: "activiti", | ||||
|         headerButtonSize: "mini", | ||||
|         // additionalModel: [] | ||||
|         additionalModel: [CustomContentPadProvider, CustomPaletteProvider] | ||||
|       }, | ||||
|       addis: { | ||||
|         CustomContentPadProvider, | ||||
|         CustomPaletteProvider | ||||
|       } | ||||
|       }, | ||||
|       // 流程模型的信息 | ||||
|       model: {}, | ||||
|     }; | ||||
|   }, | ||||
|   created() {}, | ||||
|   created() { | ||||
|     // 如果 modelId 非空,说明是修改流程模型 | ||||
|     const modelId = this.$route.query && this.$route.query.modelId | ||||
|     if (modelId) { | ||||
|       getModel(modelId).then(response => { | ||||
|         this.xmlString = response.data.bpmnXml | ||||
|         this.model = { | ||||
|           ...response.data, | ||||
|           bpmnXml: undefined, // 清空 bpmnXml 属性 | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     initModeler(modeler) { | ||||
|       setTimeout(() => { | ||||
| @@ -70,7 +85,34 @@ export default { | ||||
|       //   this.xmlString = undefined; | ||||
|       //   this.$refs.processDesigner.processRestart(); | ||||
|       // } | ||||
|     } | ||||
|     }, | ||||
|     save(bpmnXml) { | ||||
|       const data = { | ||||
|         ...this.model, | ||||
|         bpmnXml: bpmnXml, // this.bpmnXml 只是初始化流程图,后续修改无法通过它获得 | ||||
|       } | ||||
|  | ||||
|       // 修改的提交 | ||||
|       if (data.id) { | ||||
|         updateModel(data).then(response => { | ||||
|           this.msgSuccess("修改成功") | ||||
|           // 跳转回去 | ||||
|           this.close() | ||||
|         }) | ||||
|         return | ||||
|       } | ||||
|       // 添加的提交 | ||||
|       createModel(data).then(response => { | ||||
|         this.msgSuccess("保存成功") | ||||
|         // 跳转回去 | ||||
|         this.close() | ||||
|       }) | ||||
|     }, | ||||
|     /** 关闭按钮 */ | ||||
|     close() { | ||||
|       this.$store.dispatch("tagsView/delView", this.$route); | ||||
|       this.$router.push({ path: "/bpm/manager/model", query: { t: Date.now()}}) | ||||
|     }, | ||||
|   } | ||||
| }; | ||||
| </script> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV