index.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <div class="wrapper">
  3. <div class="container">
  4. <!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的,并设置ref让vue获取到element -->
  5. <div class="bpmn-container">
  6. <div class="bpmn-canvas" ref="canvas"></div>
  7. <!-- 工具栏显示的地方 -->
  8. <div class="bpmn-js-properties-panel" id="js-properties-panel"></div>
  9. </div>
  10. <!-- 把操作按钮写在这里面 -->
  11. <div class="action">
  12. <!-- 打开本地xml文件 -->
  13. <el-upload action class="upload-demo" :before-upload="openBpmn">
  14. <el-button icon="el-icon-folder-opened"></el-button>
  15. </el-upload>
  16. <!-- 重置操作 -->
  17. <el-button
  18. class="new"
  19. icon="el-icon-circle-plus"
  20. @click="newDiagram"
  21. ></el-button>
  22. <!-- 导出文件 -->
  23. <el-button icon="el-icon-download" @click="downloadBpmn"></el-button>
  24. <!-- 导出图片 -->
  25. <el-button icon="el-icon-picture" @click="downloadSvg"></el-button>
  26. <a hidden ref="downloadLink"></a>
  27. </div>
  28. </div>
  29. </div>
  30. </template>
  31. <script>
  32. // 引入相关的依赖
  33. import BpmnModeler from "bpmn-js/lib/Modeler";
  34. import xmlStr from "./mock/xmlStr"; // 这里是直接引用了xml字符串
  35. // 工具栏相关
  36. import propertiesPanelModule from "bpmn-js-properties-panel";
  37. import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
  38. import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";
  39. // 自定义panel
  40. // import propertiesProviderModule from "@/views/system/bpmn/components/properties-panel-extension/provider/authority/index";
  41. // import authorityModdleDescriptor from "@/views/system/bpmn/components/properties-panel-extension/descriptors/authority.json";
  42. // 网格插件
  43. import GridLineModule from "diagram-js-grid-bg";
  44. import ContextPadModule from "diagram-js-context-pad"; //上下文优化
  45. // 汉化
  46. import customTranslate from "./mock/customTranslate";
  47. import minimapModule from "diagram-js-minimap"; //导入小地图
  48. import "./mock/minimap.css"; //自定义小地图样式
  49. export default {
  50. name: "",
  51. components: {},
  52. created() {},
  53. mounted() {
  54. this.init();
  55. },
  56. data() {
  57. return {
  58. // bpmn建模器
  59. bpmnModeler: null,
  60. container: null,
  61. canvas: null,
  62. };
  63. },
  64. methods: {
  65. // 初始化相关方法
  66. init() {
  67. // 获取到属性ref为“canvas”的dom节点
  68. const canvas = this.$refs.canvas;
  69. // 将汉化包装成一个模块
  70. const customTranslateModule = {
  71. translate: ["value", customTranslate],
  72. };
  73. // 建模
  74. this.bpmnModeler = new BpmnModeler({
  75. container: canvas,
  76. // 加入工具栏支持
  77. propertiesPanel: {
  78. parent: "#js-properties-panel",
  79. },
  80. additionalModules: [
  81. // 工具栏模块
  82. propertiesPanelModule,
  83. propertiesProviderModule,
  84. // 汉化模块
  85. customTranslateModule,
  86. GridLineModule, //网格
  87. minimapModule, //小地图
  88. ],
  89. moddleExtensions: {
  90. camunda: camundaModdleDescriptor,
  91. // authority: authorityModdleDescriptor,
  92. },
  93. contextPad: {
  94. beauty: true,
  95. },
  96. });
  97. this.createNewDiagram(xmlStr);
  98. },
  99. async createNewDiagram(xmlStr) {
  100. try {
  101. await this.bpmnModeler.importXML(xmlStr);
  102. this.success();
  103. } catch (err) {
  104. this.$Message.error("打开模型出错,请确认该模型符合Bpmn2.0规范");
  105. }
  106. },
  107. success() {
  108. console.log(this.bpmnModeler);
  109. console.log("创建成功!");
  110. },
  111. newDiagram() {
  112. this.createNewDiagram(xmlStr);
  113. },
  114. // 文件操作相关方法
  115. downloadBpmn() {
  116. this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
  117. if (!err) {
  118. // 获取文件名
  119. const name = `${this.getFilename(xml)}.bpmn`;
  120. // 将文件名以及数据交给下载方法
  121. this.download({ name: name, data: xml });
  122. }
  123. });
  124. },
  125. downloadSvg() {
  126. this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
  127. if (!err) {
  128. // 获取文件名
  129. const name = `${this.getFilename(xml)}.svg`;
  130. // 从建模器画布中提取svg图形标签
  131. let context = "";
  132. const djsGroupAll = this.$refs.canvas.querySelectorAll(".djs-group");
  133. for (let item of djsGroupAll) {
  134. context += item.innerHTML;
  135. }
  136. // 获取svg的基本数据,长宽高
  137. const viewport = this.$refs.canvas
  138. .querySelector(".viewport")
  139. .getBBox();
  140. // 将标签和数据拼接成一个完整正常的svg图形
  141. const svg = `
  142. <svg
  143. xmlns="http://www.w3.org/2000/svg"
  144. xmlns:xlink="http://www.w3.org/1999/xlink"
  145. width="${viewport.width}"
  146. height="${viewport.height}"
  147. viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
  148. version="1.1"
  149. >
  150. ${context}
  151. </svg>
  152. `;
  153. // 将文件名以及数据交给下载方法
  154. this.download({ name: name, data: svg });
  155. }
  156. });
  157. },
  158. openBpmn(file) {
  159. const reader = new FileReader();
  160. // 读取File对象中的文本信息,编码格式为UTF-8
  161. reader.readAsText(file, "utf-8");
  162. reader.onload = () => {
  163. //读取完毕后将文本信息导入到Bpmn建模器
  164. this.createNewDiagram(reader.result);
  165. };
  166. return false;
  167. },
  168. getFilename(xml) {
  169. let start = xml.indexOf("process");
  170. let filename = xml.substr(start, xml.indexOf(">"));
  171. filename = filename.substr(filename.indexOf("id") + 4);
  172. filename = filename.substr(0, filename.indexOf('"'));
  173. return filename;
  174. },
  175. download({ name = "diagram.bpmn", data }) {
  176. // 这里就获取到了之前设置的隐藏链接
  177. const downloadLink = this.$refs.downloadLink;
  178. // 把数据转换为URI,下载要用到的
  179. const encodedData = encodeURIComponent(data);
  180. if (data) {
  181. // 将数据给到链接
  182. downloadLink.href =
  183. "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
  184. // 设置文件名
  185. downloadLink.download = name;
  186. // 触发点击事件开始下载
  187. downloadLink.click();
  188. }
  189. },
  190. },
  191. };
  192. </script>
  193. <style scoped lang="scss">
  194. .wrapper {
  195. height: calc(100vh - 173px);
  196. }
  197. .container {
  198. position: relative;
  199. height: 100%;
  200. }
  201. .bpmn-container {
  202. width: 100%;
  203. height: 100%;
  204. display: flex;
  205. }
  206. .bpmn-canvas {
  207. width: calc(100% - 300px);
  208. height: 100%;
  209. }
  210. .bpmn-js-properties-panel {
  211. width: 320px;
  212. height: inherit;
  213. overflow-y: auto;
  214. }
  215. .action {
  216. position: fixed;
  217. top: 135px;
  218. left: 50%;
  219. transform: translate(-50%);
  220. display: flex;
  221. }
  222. .upload-demo {
  223. margin-right: 10px;
  224. }
  225. </style>