├── imgAndDoc ├── .gitignore └── img │ ├── output.jpg │ ├── output_small.jpg │ ├── food_product_flow.jpg │ └── food_product_flow_small.jpg ├── flow_designer ├── .gitignore └── WebContent │ ├── css │ └── designer.css │ ├── imgs │ └── design │ │ ├── cog.png │ │ ├── anyone.gif │ │ ├── node.png │ │ ├── result.gif │ │ ├── trash.png │ │ ├── paiallel.gif │ │ ├── sequence.gif │ │ ├── sub_flow.png │ │ ├── Blue Ball.png │ │ ├── Blue Ball16.png │ │ ├── Orange Ball.png │ │ ├── anyone_auto.gif │ │ ├── anyone_gray.gif │ │ ├── menus │ │ ├── broom.png │ │ ├── disk.png │ │ ├── print.png │ │ ├── publish.png │ │ ├── property.png │ │ ├── cross-circle.png │ │ ├── folder-plus.png │ │ ├── printer_set.png │ │ ├── tick-circle.png │ │ ├── folder-open-image-disk.png │ │ ├── folder-open-image-network.png │ │ ├── document-attribute-x-export.png │ │ └── document-attribute-x-download.png │ │ ├── mouse_add.png │ │ ├── result_auto.gif │ │ ├── time_driven.png │ │ ├── anyone_start.gif │ │ ├── arrow_refresh.png │ │ ├── paiallel_gray.gif │ │ ├── result_break.gif │ │ ├── sequence_gray.gif │ │ ├── arrow_refresh_v.png │ │ ├── sub_flow_anyone.png │ │ ├── sub_flow_paiallel.png │ │ └── sub_flow_sequence.png │ ├── index.html │ ├── js │ ├── file_save.js │ ├── base64.js │ └── modal.js │ ├── xmlCreator.js │ ├── xmlPareser.js │ ├── dragController.js │ ├── example │ └── example1.xml │ ├── designer.html │ └── designer.js ├── README.md ├── CODE_OF_CONDUCT.md └── LICENSE /imgAndDoc/.gitignore: -------------------------------------------------------------------------------- 1 | /.project 2 | -------------------------------------------------------------------------------- /flow_designer/.gitignore: -------------------------------------------------------------------------------- 1 | /.project 2 | /.settings/ -------------------------------------------------------------------------------- /imgAndDoc/img/output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/output.jpg -------------------------------------------------------------------------------- /imgAndDoc/img/output_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/output_small.jpg -------------------------------------------------------------------------------- /imgAndDoc/img/food_product_flow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/food_product_flow.jpg -------------------------------------------------------------------------------- /flow_designer/WebContent/css/designer.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/css/designer.css -------------------------------------------------------------------------------- /imgAndDoc/img/food_product_flow_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/food_product_flow_small.jpg -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/cog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/cog.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/anyone.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/node.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/trash.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/paiallel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/paiallel.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sequence.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sequence.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sub_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/Blue Ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Blue Ball.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/Blue Ball16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Blue Ball16.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/Orange Ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Orange Ball.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/anyone_auto.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_auto.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/anyone_gray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_gray.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/broom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/broom.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/disk.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/print.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/mouse_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/mouse_add.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/result_auto.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result_auto.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/time_driven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/time_driven.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/anyone_start.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_start.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/arrow_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/arrow_refresh.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/publish.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/paiallel_gray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/paiallel_gray.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/result_break.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result_break.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sequence_gray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sequence_gray.gif -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/arrow_refresh_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/arrow_refresh_v.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/property.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sub_flow_anyone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_anyone.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/cross-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/cross-circle.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/folder-plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-plus.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/printer_set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/printer_set.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/tick-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/tick-circle.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sub_flow_paiallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_paiallel.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/sub_flow_sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_sequence.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/folder-open-image-disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-open-image-disk.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/folder-open-image-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-open-image-network.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/document-attribute-x-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/document-attribute-x-export.png -------------------------------------------------------------------------------- /flow_designer/WebContent/imgs/design/menus/document-attribute-x-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/document-attribute-x-download.png -------------------------------------------------------------------------------- /flow_designer/WebContent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 流程模型管理 6 | 7 | 8 |

点击此处进入流程编辑页面。 9 |

注意:目前支持以下浏览器:chrome,firefox,opera. 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License](https://img.shields.io/badge/license-anti996-green.svg)](https://github.com/wanlinus/Anti996-License/blob/master/LICENSE) 2 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](https://github.com/xiaoke1256/FlowDesigner/blob/master/LICENSE) 3 | 4 | FlowDesigner 5 | === 6 | 一个用H5实现的工作流引擎的可视化编辑器。可在其上绘制一个流程图。完成绘制后可以以xml文件导出。 7 | -------------------------------------------------------------------------------- /flow_designer/WebContent/js/file_save.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 本函数用于向本地导出文件。 3 | * @param content 文件内容 4 | * @param type 文件类型,取值类似"text/plain;charset=utf-8" 5 | * @param fileName 文件名 6 | * @returns 7 | */ 8 | function saveFile(content, type, fileName) { 9 | var blob; 10 | if (typeof window.Blob == "function") { 11 | blob = new Blob([content], {type: type}); 12 | } else { 13 | var BlobBuilder = window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder; 14 | var bb = new BlobBuilder(); 15 | bb.append(content); 16 | blob = bb.getBlob(type); 17 | } 18 | var URL = window.URL || window.webkitURL; 19 | var bloburl = URL.createObjectURL(blob); 20 | var anchor = document.createElement("a"); 21 | if ('download' in anchor) { 22 | anchor.style.visibility = "hidden"; 23 | anchor.href = bloburl; 24 | anchor.download = fileName; 25 | document.body.appendChild(anchor); 26 | var evt = document.createEvent("MouseEvents"); 27 | evt.initEvent("click", true, true); 28 | anchor.dispatchEvent(evt); 29 | document.body.removeChild(anchor); 30 | window.URL.revokeObjectURL(anchor.href); 31 | } else if (navigator.msSaveBlob) { 32 | navigator.msSaveBlob(blob, fileName); 33 | } else { 34 | location.href = bloburl; 35 | } 36 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at xiaoke_1256@sina.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /flow_designer/WebContent/js/base64.js: -------------------------------------------------------------------------------- 1 | function Base64() { 2 | 3 | // private property 4 | _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 5 | 6 | // public method for encoding 7 | this.encode = function (input) { 8 | var output = ""; 9 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 10 | var i = 0; 11 | input = _utf8_encode(input); 12 | while (i < input.length) { 13 | chr1 = input.charCodeAt(i++); 14 | chr2 = input.charCodeAt(i++); 15 | chr3 = input.charCodeAt(i++); 16 | enc1 = chr1 >> 2; 17 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 18 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 19 | enc4 = chr3 & 63; 20 | if (isNaN(chr2)) { 21 | enc3 = enc4 = 64; 22 | } else if (isNaN(chr3)) { 23 | enc4 = 64; 24 | } 25 | output = output + 26 | _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + 27 | _keyStr.charAt(enc3) + _keyStr.charAt(enc4); 28 | } 29 | return output; 30 | } 31 | 32 | // public method for decoding 33 | this.decode = function (input) { 34 | var output = ""; 35 | var chr1, chr2, chr3; 36 | var enc1, enc2, enc3, enc4; 37 | var i = 0; 38 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 39 | while (i < input.length) { 40 | enc1 = _keyStr.indexOf(input.charAt(i++)); 41 | enc2 = _keyStr.indexOf(input.charAt(i++)); 42 | enc3 = _keyStr.indexOf(input.charAt(i++)); 43 | enc4 = _keyStr.indexOf(input.charAt(i++)); 44 | chr1 = (enc1 << 2) | (enc2 >> 4); 45 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 46 | chr3 = ((enc3 & 3) << 6) | enc4; 47 | output = output + String.fromCharCode(chr1); 48 | if (enc3 != 64) { 49 | output = output + String.fromCharCode(chr2); 50 | } 51 | if (enc4 != 64) { 52 | output = output + String.fromCharCode(chr3); 53 | } 54 | } 55 | output = _utf8_decode(output); 56 | return output; 57 | } 58 | 59 | // private method for UTF-8 encoding 60 | _utf8_encode = function (string) { 61 | string = string.replace(/\r\n/g,"\n"); 62 | var utftext = ""; 63 | for (var n = 0; n < string.length; n++) { 64 | var c = string.charCodeAt(n); 65 | if (c < 128) { 66 | utftext += String.fromCharCode(c); 67 | } else if((c > 127) && (c < 2048)) { 68 | utftext += String.fromCharCode((c >> 6) | 192); 69 | utftext += String.fromCharCode((c & 63) | 128); 70 | } else { 71 | utftext += String.fromCharCode((c >> 12) | 224); 72 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 73 | utftext += String.fromCharCode((c & 63) | 128); 74 | } 75 | 76 | } 77 | return utftext; 78 | } 79 | 80 | // private method for UTF-8 decoding 81 | _utf8_decode = function (utftext) { 82 | var string = ""; 83 | var i = 0; 84 | var c = c1 = c2 = 0; 85 | while ( i < utftext.length ) { 86 | c = utftext.charCodeAt(i); 87 | if (c < 128) { 88 | string += String.fromCharCode(c); 89 | i++; 90 | } else if((c > 191) && (c < 224)) { 91 | c2 = utftext.charCodeAt(i+1); 92 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 93 | i += 2; 94 | } else { 95 | c2 = utftext.charCodeAt(i+1); 96 | c3 = utftext.charCodeAt(i+2); 97 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); 98 | i += 3; 99 | } 100 | } 101 | return string; 102 | } 103 | } 104 | 105 | /** 106 | * 把base64数组转成byte数组 107 | * @returns 108 | */ 109 | function base64ToBytes(base64){ 110 | var arr = base64.split(',') , mime = arr[0].match(/:(.*?);/)[1] , bstr = atob(arr[1]) , n = bstr.length , u8arr = new Uint8Array(n); 111 | while (n--) { 112 | u8arr[n] = bstr.charCodeAt(n); 113 | } 114 | return u8arr; 115 | } -------------------------------------------------------------------------------- /flow_designer/WebContent/js/modal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用jQuery实现一个模态对话框 3 | * 本模块依赖于 jQuery 4 | */ 5 | 6 | 7 | 8 | (function($){ 9 | //滚动条的宽度,页面加载时就获取 10 | var scrollWidth = 0; 11 | $(function(){ 12 | scrollWidth = getScrollWidth(); 13 | }); 14 | 15 | //默认的长和宽 16 | var defaultSize = {width:600,height:220}; 17 | 18 | /**模态对话框对象*/ 19 | var modalObj = null; 20 | 21 | $.extend({ 22 | modal:function(html,size){ 23 | size = $.extend(defaultSize,size); 24 | //获取整个页面可视区域的大小 25 | var cWidth = $(window).width(); 26 | var cHeight = $(window).height(); 27 | console.log("scrollWidth:"+scrollWidth); 28 | //先创建一个蒙板,蒙住整个页面。 29 | var mask = $('

'); 30 | mask.width(cWidth); 31 | mask.height(cHeight); 32 | mask.css('background','#999'); 33 | $('body').append(mask); 34 | 35 | //页面正中放一个dev作为模态框。 36 | var $modal = $(''); 37 | if(html){ 38 | $modal.html(html); 39 | } 40 | $modal.width(size.width); 41 | $modal.height(size.height); 42 | var left = (cWidth-size.width)/2; 43 | if(left< 20) 44 | left = 20; 45 | var top = (cHeight-size.height)/2; 46 | if(top< 10) 47 | top = 10; 48 | $modal.css("left",left); 49 | $modal.css("top",top); 50 | $('body').append($modal); 51 | 52 | //窗口大小变更,蒙板尺寸要跟着变 53 | var hasYScoll = hasYScrollbar(mask[0]);//是否存在纵向的滚动条。 54 | var hasXScoll = hasXScrollbar(mask[0]); 55 | var resizeEve = function(){ 56 | var nWidth = $(window).width(); 57 | var nHeight = $(window).height(); 58 | var newHasYScoll = hasYScrollbar(mask[0]); 59 | var newHasXScoll = hasXScrollbar(mask[0]); 60 | //console.log("newHasYScoll:"+newHasYScoll+" hasYScoll:"+hasYScoll); 61 | if(!hasYScoll && newHasYScoll){//原先没的 后来有了 62 | console.log("纵向滚动条原先没的 后来有了"); 63 | nWidth += scrollWidth; 64 | hasYScoll = false;//修正后应当没有滚动条了 65 | }else{ 66 | hasYScoll = newHasYScoll; 67 | } 68 | if(!hasXScoll && newHasXScoll){//原先没的 后来有了 69 | console.log("横向滚动条原先没的 后来有了"); 70 | nHeight += scrollWidth; 71 | hasXScoll = false;//修正后应当没有滚动条了 72 | }else{ 73 | hasXScoll = newHasXScoll; 74 | } 75 | console.log("最终蒙版的高度:"+nHeight); 76 | mask.width(nWidth); 77 | mask.height(nHeight); 78 | 79 | //模态对话框的位置也要跟着变。 80 | var left = (nWidth-size.width)/2; 81 | if(left< 20) 82 | left = 20; 83 | var top = (nHeight-size.height)/2; 84 | if(top< 10) 85 | top = 10; 86 | $modal.css("left",left); 87 | $modal.css("top",top); 88 | } 89 | $(window).resize(resizeEve); 90 | 91 | //滚动条滚动了,蒙版位置要跟着变。 92 | var scrollEve = function() { 93 | var scroH = $(document).scrollTop();//滚动的高度 94 | var scroV = $(document).scrollLeft();//滚动的居左位置 95 | mask.css("top",scroH); 96 | mask.css("left",scroV); 97 | 98 | //模态对话框的位置也要跟着变。 99 | $modal.css("left",left+scroV); 100 | $modal.css("top",top+scroH); 101 | } 102 | $(document).scroll(scrollEve); 103 | 104 | //返回模态窗口对象 105 | modalObj = { 106 | /*关闭模态对话框*/ 107 | closed:function(){ 108 | //删除模态对话框 109 | $modal.remove(); 110 | //删除蒙板 111 | mask.remove(); 112 | //注销窗口变化事件 113 | $(window).off('resize',resizeEve); 114 | //注销滚动条变化事件 115 | $(document).off('scroll',scrollEve); 116 | } 117 | }; 118 | return modalObj; 119 | }, 120 | closeModal:function(){ 121 | if(modalObj){ 122 | modalObj.closed(); 123 | } 124 | } 125 | }); 126 | 127 | })(jQuery); 128 | 129 | /** 130 | * 是否有纵向的滚动条 131 | * @returns 132 | */ 133 | function hasYScrollbar(mask) { 134 | var height = 0; 135 | if(mask){ 136 | height = mask.scrollHeight; 137 | } 138 | height = Math.max(height,document.body.scrollHeight); 139 | //console.log("scrollHeight:"+mask.scrollHeight+ " innerHeight:"+(window.innerHeight || document.documentElement.clientHeight) ) 140 | return height > document.documentElement.clientHeight; 141 | } 142 | /** 143 | * 是否有横向的滚动条 144 | * @returns 145 | */ 146 | function hasXScrollbar(mask) { 147 | var width = 0; 148 | if(mask){ 149 | width = $(mask).outerWidth(true); 150 | } 151 | width = Math.max(width,document.body.scrollWidth); 152 | console.log("width:"+width+" clientWidth: "+document.documentElement.clientWidth); 153 | return width > document.documentElement.clientWidth; 154 | } 155 | 156 | /** 157 | * 获取滚动条的宽度 158 | * @returns 159 | */ 160 | function getScrollWidth() { 161 | var noScroll, scroll, oDiv = document.createElement("DIV"); 162 | oDiv.style.cssText = "position:absolute;top:-1000px;width:100px;height:100px; overflow:hidden;"; 163 | noScroll = document.body.appendChild(oDiv).clientWidth; 164 | oDiv.style.overflowY = "scroll"; 165 | scroll = oDiv.clientWidth; 166 | document.body.removeChild(oDiv); 167 | return noScroll-scroll; 168 | } 169 | 170 | 171 | -------------------------------------------------------------------------------- /flow_designer/WebContent/xmlCreator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 把流程模型转成xml的js. 3 | */ 4 | function flModelToXml(flModel){ 5 | var xmlDOM = createXMLDOM(); 6 | if (xmlDOM) { 7 | //创建根节点 8 | var rootNode = xmlDOM.createElement('esflow'); 9 | xmlDOM.appendChild(rootNode); 10 | 11 | var flowInfoModel = flModel.flowInfo.model; 12 | //创建流程节点 13 | var flowNode = xmlDOM.createElement('flow'); 14 | for(var prop in flowInfoModel){ 15 | flowNode.setAttribute(prop,flowInfoModel[prop]); 16 | } 17 | rootNode.appendChild(flowNode); 18 | 19 | //创建活动节点 20 | var actsNode = xmlDOM.createElement('activities'); 21 | flowNode.appendChild(actsNode); 22 | 23 | bizObjsToXmlNode(xmlDOM,flModel.activities,'activity',actsNode); 24 | 25 | //创建结果节点 26 | var opersNode = xmlDOM.createElement('operations'); 27 | flowNode.appendChild(opersNode); 28 | 29 | bizObjsToXmlNode(xmlDOM,flModel.operations,'operation',opersNode); 30 | 31 | //创建后续节点 32 | var subseqsNode = xmlDOM.createElement('subsequents'); 33 | flowNode.appendChild(subseqsNode); 34 | 35 | bizObjsToXmlNode(xmlDOM,flModel.subsequents,'subsequent',subseqsNode) 36 | 37 | return xmlFormat(parserXMLToString(xmlDOM)); 38 | } 39 | } 40 | 41 | /** 42 | * 把一批业务对象转成xml节点 43 | * @returns 44 | */ 45 | function bizObjsToXmlNode(xmlDOM,bizes,tagName,parentNode){ 46 | for(var i in bizes){ 47 | var biz = bizes[i]; 48 | var bizNode = xmlDOM.createElement(tagName); 49 | var modelNode = xmlDOM.createElement('model'); 50 | var viewNode = xmlDOM.createElement('view'); 51 | for(var prop in biz.model){ 52 | propNode = xmlDOM.createElement(prop); 53 | textNode = xmlDOM.createTextNode(biz.model[prop]); 54 | propNode.appendChild(textNode); 55 | modelNode.appendChild(propNode); 56 | } 57 | for(var prop in biz.view){ 58 | propNode = xmlDOM.createElement(prop); 59 | textNode = xmlDOM.createTextNode(biz.view[prop]); 60 | propNode.appendChild(textNode); 61 | viewNode.appendChild(propNode); 62 | } 63 | bizNode.appendChild(modelNode); 64 | bizNode.appendChild(viewNode); 65 | parentNode.appendChild(bizNode); 66 | } 67 | } 68 | 69 | /** 70 | * 创建 XMLDOM 71 | * @returns xmlDOM 72 | */ 73 | function createXMLDOM() { 74 | var xmlDOM; 75 | if (window.ActiveXObject) { 76 | xmlDOM = new ActiveXObject('Microsoft.XMLDOM'); 77 | } else if (document.implementation 78 | && document.implementation.createDocument) { 79 | xmlDOM = document.implementation.createDocument('', '', null); 80 | } else { 81 | alert('您的浏览器不支持文档对象XMLDOM'); 82 | return; 83 | } 84 | return xmlDOM; 85 | } 86 | 87 | /** 88 | * 把XMLDOM解析成字符串 89 | * @param xmlDOM 90 | * @returns 91 | */ 92 | function parserXMLToString(xmlDOM) { 93 | if (window.ActiveXObject) { 94 | return xmlDOM.xml; 95 | } else if (document.implementation 96 | && document.implementation.createDocument) { 97 | return new XMLSerializer().serializeToString(xmlDOM); 98 | } 99 | } 100 | 101 | /** 102 | * 把xml格式化一下 103 | * @param xml 104 | * @returns 105 | */ 106 | function xmlFormat(xml){ 107 | if(!xml){ 108 | return xml; 109 | } 110 | xml = $.trim(xml); 111 | var prefix = ''; 112 | if(xml.indexOf('\n\n'; 114 | } 115 | var sp = 0;//缩进 116 | var preTagName = ''; //上次循环处理的TagName 117 | var preStartTagFlage = false;//true为 false 为 ,null为 . 118 | var index = xml.indexOf('<',0); 119 | while(index>=0){ 120 | //console.log(index+" char At(index+1):"+xml.charAt(index+1)); 121 | var tagEndIndex = xml.indexOf('>',index+1); 122 | //console.log("end Tag index:"+tagEndIndex); 123 | var tagName = xml.substring(index+1,tagEndIndex); 124 | //console.log("tagName:"+tagName); 125 | var startTagFlage = false; 126 | if(tagName.charAt(0)=='/'){ 127 | //需要出栈 128 | console.log("出栈."); 129 | startTagFlage = false; 130 | tagName = tagName.substring(1); 131 | }else if(tagName.charAt(tagName.length-1)=='/'){ 132 | //不出栈也不入栈 133 | console.log("不出栈也不入栈."); 134 | startTagFlage = null; 135 | tagName = tagName.substring(0,tagName.length-1); 136 | }else{ 137 | console.log("入栈."); 138 | //需要入栈 139 | startTagFlage = true; 140 | } 141 | console.log("tagName:"+tagName); 142 | if(startTagFlage==null){ 143 | //要换行, 144 | //sp+=2; 145 | }else if(!startTagFlage ){ 146 | sp -= 2; 147 | //上次为入栈且处理的标签是一样的。 148 | if(preStartTagFlage && preTagName == tagName){ 149 | //不用换行处理 150 | index = xml.indexOf('<',index+1); 151 | continue; 152 | } 153 | 154 | }else if(startTagFlage){ 155 | //不处理后续再处理。 156 | } 157 | //在index位置插入一个换行符和若干个空格 158 | //console.log("sp:"+sp); 159 | var spaces = ''; 160 | for(var i=0;i0?sp:0)+1); 173 | index = xml.indexOf('<',index+1); 174 | } 175 | 176 | return prefix+xml; 177 | } 178 | 179 | -------------------------------------------------------------------------------- /flow_designer/WebContent/xmlPareser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 把xml的内容转成Doc对象 3 | * @returns 4 | */ 5 | function loadXML(xmlString){ 6 | var xmlDoc = null ; 7 | // 判断浏览器的类型 8 | // 支持IE浏览器 9 | if ( ! window.DOMParser && window.ActiveXObject){ // window.DOMParser 判断是否是非ie浏览器 10 | var xmlDomVersions = [ ' MSXML.2.DOMDocument.6.0 ' , ' MSXML.2.DOMDocument.3.0 ' , ' Microsoft.XMLDOM ' ]; 11 | for ( var i = 0 ;i < xmlDomVersions.length;i ++ ){ 12 | try { 13 | xmlDoc = new ActiveXObject(xmlDomVersions[i]); 14 | xmlDoc.async = false ; 15 | xmlDoc.loadXML(xmlString); // loadXML方法载入xml字符串 16 | break ; 17 | } catch (e){ 18 | } 19 | } 20 | } 21 | // 支持Mozilla浏览器 22 | else if (window.DOMParser && document.implementation && document.implementation.createDocument){ 23 | try { 24 | /* DOMParser 对象解析 XML 文本并返回一个 XML Document 对象。 25 | * 要使用 DOMParser,使用不带参数的构造函数来实例化它,然后调用其 parseFromString() 方法 26 | * parseFromString(text, contentType) 参数text:要解析的 XML 标记 参数contentType文本的内容类型 27 | * 可能是 "text/xml" 、"application/xml" 或 "application/xhtml+xml" 中的一个。注意,不支持 "text/html"。 28 | */ 29 | domParser = new DOMParser(); 30 | xmlDoc = domParser.parseFromString(xmlString, 'text/xml' ); 31 | } catch (e){ 32 | console.error(e); 33 | throw e; 34 | } 35 | } 36 | else { 37 | return null ; 38 | } 39 | 40 | return xmlDoc; 41 | } 42 | 43 | /**把xml文档转成一个对象*/ 44 | function xmlDocToObj(xmlDoc){ 45 | var flowModle = { 46 | flowInfo:{model:{},view:{}}, 47 | activities:[],/*活动*/ 48 | operations:[],/*操作结果*/ 49 | subsequents:[] /*后续线*/ 50 | }; 51 | var flowInfoModel = flowModle.flowInfo.model; 52 | var nodes = xmlDoc.getElementsByTagName("flow") 53 | if(!nodes || nodes.length==0){ 54 | throw "xml 解析异常,未找到 flow 节点。"; 55 | } 56 | var flowNode = nodes[0]; 57 | console.log("flowNode.attributes:"+flowNode.attributes); 58 | var flowId = flowNode.getAttribute("flowId"); 59 | var version = flowNode.getAttribute("version"); 60 | var flowName = flowNode.getAttribute("flowName"); 61 | var displayName = flowNode.getAttribute("displayName"); 62 | var description = flowNode.getAttribute("description"); 63 | flowInfoModel.flowId = flowId; 64 | flowInfoModel.version = version; 65 | flowInfoModel.flowName = flowName; 66 | flowInfoModel.displayName = displayName; 67 | flowInfoModel.description = description; 68 | 69 | //处理各个环节 70 | var nodes = flowNode.getElementsByTagName("activities"); 71 | if(!nodes || nodes.length==0){ 72 | throw "xml 解析异常,未找到 activities 节点。"; 73 | } 74 | var actsNode = nodes[0]; 75 | var actNodes = actsNode.getElementsByTagName("activity"); 76 | if(!actNodes || actNodes.length==0){ 77 | throw "xml 解析异常,未找到 activity 节点。"; 78 | } 79 | for(var i in actNodes){ 80 | var actNode = actNodes[i]; 81 | 82 | var act = bizNodeToObj(actNode); 83 | if(act) 84 | flowModle.activities.push(act); 85 | } 86 | 87 | //处理各个结果 88 | var nodes = flowNode.getElementsByTagName("operations"); 89 | if(!nodes || nodes.length==0){ 90 | throw "xml 解析异常,未找到 operations 节点。"; 91 | } 92 | var opersNode = nodes[0]; 93 | var operNodes = opersNode.getElementsByTagName("operation"); 94 | if(!operNodes || operNodes.length==0){ 95 | throw "xml 解析异常,未找到 operation 节点。"; 96 | } 97 | for(var i in operNodes){ 98 | var operNode = operNodes[i]; 99 | 100 | var oper = bizNodeToObj(operNode); 101 | if(oper) 102 | flowModle.operations.push(oper); 103 | } 104 | 105 | //处理各个后续线 106 | var nodes = flowNode.getElementsByTagName("subsequents"); 107 | if(!nodes || nodes.length==0){ 108 | throw "xml 解析异常,未找到 operations 节点。"; 109 | } 110 | var subseqsNode = nodes[0]; 111 | var subseqNodes = subseqsNode.getElementsByTagName("subsequent"); 112 | for(var i in subseqNodes){ 113 | var subseqNode = subseqNodes[i]; 114 | 115 | var subseq = bizNodeToObj(subseqNode); 116 | if(subseq) 117 | flowModle.subsequents.push(subseq); 118 | } 119 | 120 | return flowModle; 121 | } 122 | 123 | /** 124 | * 把xml中的业务节点转成业务对象。 125 | * @param bizNode 126 | * @returns 127 | */ 128 | function bizNodeToObj(bizNode){ 129 | if(typeof(bizNode.getElementsByTagName)!='function' ){ 130 | console.log("getElementsByTagName is not a function! "+typeof(bizNode.getElementsByTagName)); 131 | } 132 | var childNodes = bizNode.children; 133 | if(!childNodes){ 134 | console.warn("childNodes 居然为空!!text:"+bizNode.text); 135 | return null; 136 | } 137 | if(childNodes.length<2){ 138 | throw "xml 解析异常,一个业务对象应当既包含model节点,又包含view节点。"; 139 | } 140 | var modelNode =childNodes[0]; 141 | var viewNode =childNodes[1]; 142 | if(modelNode.nodeName!='model'){ 143 | throw "xml 解析异常,activity 下未找到 model 节点。"; 144 | } 145 | if(viewNode.nodeName!='view'){ 146 | throw "xml 解析异常,activity 下未找到 view 节点。"; 147 | } 148 | var model = {}; 149 | var view = {}; 150 | var propNodes = modelNode.children; 151 | for(var j in propNodes){ 152 | if(!propNodes[j].nodeName) 153 | continue; 154 | model[propNodes[j].nodeName]=propNodes[j].textContent ; 155 | //console.log("针对字段“"+propNodes[j].nodeName+"”设置了值“"+propNodes[j].textContent +"”"); 156 | } 157 | var propNodes = viewNode.children; 158 | for(var j in propNodes){ 159 | if(!propNodes[j].nodeName) 160 | continue; 161 | view[propNodes[j].nodeName]=parseInt(propNodes[j].textContent) ; 162 | //console.log("针对字段“"+propNodes[j].nodeName+"”设置了值“"+parseInt(propNodes[j].textContent) +"”"); 163 | } 164 | return {model:model,view:view}; 165 | } -------------------------------------------------------------------------------- /flow_designer/WebContent/dragController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 本js文件定义了,鼠标拖动的控制器。 3 | * 包含两个控制器,一个是默认的,一个是调整坐标系时用的。 4 | * 本js程序依赖于以下程序: 5 | * jQuery.js 6 | */ 7 | 8 | /** 9 | * 默认的鼠标拖动控制器 10 | */ 11 | var getDefaultDragCtrl = function(renderCtx){ 12 | 13 | var flRender = renderCtx; 14 | 15 | /**结束鼠标拖动事件*/ 16 | function _onEndDrag(obj){ 17 | //如果拖动的是控制点的话需要处理 18 | if(obj instanceof ControlPoint){ 19 | var redMarked = flRender.getRedMarked(); 20 | //看是否拖动到了某个对象内 21 | if(!redMarked){ 22 | resetControlPoint(obj.parent); 23 | return; 24 | } 25 | if(obj.parent instanceof Oper){ 26 | var target = redMarked; 27 | if(!(target instanceof Act)){//一个结果必须与一个活动关联. 28 | resetControlPoint(obj.parent); 29 | return; 30 | } 31 | if(!target.model.activityId){ 32 | showErrMsg('请先填写“活动代码”。'); 33 | resetControlPoint(obj.parent); 34 | return; 35 | } 36 | obj.parent.model.activityId = target.model.activityId; 37 | obj.parent.view.controlPoint = null; 38 | } 39 | if(obj.parent instanceof Subsequent){ 40 | var target = redMarked; 41 | if (target instanceof Act){ 42 | if(!target.model.activityId){ 43 | showErrMsg('请先填写“活动代码”。'); 44 | resetControlPoint(obj.parent,obj); 45 | return; 46 | } 47 | if(obj.parent.model.activityId){ 48 | showErrMsg('后续线应当一头连接活动,一头连接结果。'); 49 | resetControlPoint(obj.parent,obj); 50 | return; 51 | } 52 | obj.parent.model.activityId = target.model.activityId; 53 | if(obj.parent.view.controlPoint===obj){ 54 | obj.parent.view.controlPoint = null; 55 | }else if(obj.parent.view.controlPoint1===obj){ 56 | obj.parent.view.controlPoint1 = null; 57 | } 58 | } 59 | if (target instanceof Oper){ 60 | if(!target.model.operationId){ 61 | showErrMsg('请先填写“结果代码”。'); 62 | resetControlPoint(obj.parent,obj); 63 | return; 64 | } 65 | if(obj.parent.model.operationId){ 66 | showErrMsg('后续线应当一头连接活动,一头连接结果。'); 67 | resetControlPoint(obj.parent,obj); 68 | return; 69 | } 70 | obj.parent.model.operationId = target.model.operationId; 71 | if(obj.parent.view.controlPoint===obj){ 72 | obj.parent.view.controlPoint = null; 73 | }else if(obj.parent.view.controlPoint1===obj){ 74 | obj.parent.view.controlPoint1 = null; 75 | } 76 | } 77 | } 78 | 79 | } 80 | } 81 | 82 | /**业务对象被拖动事件*/ 83 | function _onBusinessObjDrag(bizObj,beforePos,afterPos){ 84 | bizObj.view.x=bizObj.view.x+afterPos.x-beforePos.x; 85 | bizObj.view.y=bizObj.view.y+afterPos.y-beforePos.y; 86 | if(bizObj.view.controlPoint){ 87 | bizObj.view.controlPoint.x = bizObj.view.controlPoint.x+afterPos.x-beforePos.x; 88 | bizObj.view.controlPoint.y = bizObj.view.controlPoint.y+afterPos.y-beforePos.y; 89 | } 90 | if(bizObj.view.controlPoint1){ 91 | bizObj.view.controlPoint1.x = bizObj.view.controlPoint1.x+afterPos.x-beforePos.x; 92 | bizObj.view.controlPoint1.y = bizObj.view.controlPoint1.y+afterPos.y-beforePos.y; 93 | } 94 | } 95 | /**控制点被拖动事件*/ 96 | function _onControlPointDrag(controlPoint,beforePos,afterPos){ 97 | var flowModle = flRender.getFlowModle(); 98 | controlPoint.x = controlPoint.x + afterPos.x-beforePos.x; 99 | controlPoint.y = controlPoint.y + afterPos.y-beforePos.y; 100 | //标红 101 | for(var i in flowModle.activities){ 102 | var act = flowModle.activities[i]; 103 | var view = act.view; 104 | if(view.x < afterPos.x && afterPos.x < view.x + view.width 105 | && view.y < afterPos.y && afterPos.y < view.y + view.height ){ 106 | console.log('actact'); 107 | flRender.setRedMarked(act); 108 | return; 109 | } 110 | } 111 | for(var i in flowModle.operations){ 112 | var oper = flowModle.operations[i]; 113 | var view = oper.view; 114 | if(view.x < afterPos.x && afterPos.x < view.x + view.width 115 | && view.y < afterPos.y && afterPos.y < view.y + view.height ){ 116 | console.log('oper selected : '+(oper instanceof Oper)); 117 | flRender.setRedMarked(oper); 118 | return; 119 | } 120 | } 121 | //没有拖动到任何对象内则取消标红 122 | flRender.setRedMarked(null); 123 | } 124 | 125 | return { 126 | /**开始拖动事件*/ 127 | onStartDrag:function (obj){ 128 | //do nothing. 129 | }, 130 | /**结束拖动鼠标事件*/ 131 | onEndDrag:function(obj){ 132 | _onEndDrag(obj); 133 | }, 134 | /**拖动事件*/ 135 | onDrag:function(obj,beforePos,afterPos){ 136 | if(!obj) 137 | return; 138 | if(obj instanceof BussinessObj){ 139 | _onBusinessObjDrag(obj,beforePos,afterPos); 140 | }else if(obj instanceof ControlPoint){ 141 | _onControlPointDrag(obj,beforePos,afterPos); 142 | } 143 | }, 144 | /**右击事件*/ 145 | rightClick:function(obj){ 146 | //先把业务对象选中 147 | flRender.resetSelected(obj); 148 | //然后将右键菜单显示出来 149 | //将右键菜单挪到鼠标所在的位置 150 | var x = event.pageX; 151 | var y = event.pageY; 152 | var rightMenuDiv = null; 153 | if(obj instanceof Act){ 154 | rightMenuDiv = $('#rightMenuForAct'); 155 | }else if(obj instanceof Oper){ 156 | rightMenuDiv = $('#rightMenuForOper'); 157 | }else if(obj instanceof Subsequent){ 158 | rightMenuDiv = $('#rightMenuForSubseq'); 159 | }else{ 160 | return; 161 | } 162 | rightMenuDiv.css("left",x); 163 | rightMenuDiv.css("top",y); 164 | rightMenuDiv.show(); 165 | } 166 | } 167 | }; 168 | 169 | //为了配合上述处理把浏览器默认的右键菜单禁用掉. 170 | $(function(){ 171 | //把浏览器默认的右键菜单禁用掉. 172 | $('.rightMenu').bind("contextmenu", function(){ 173 | return false; 174 | }); 175 | //点击任何地方,就把右键菜单隐藏起来. 176 | $('body').click(function(){ 177 | $('.rightMenu').hide(); 178 | }) 179 | }); 180 | 181 | /** 182 | * 把控制点调整到默认位置。 183 | * @param obj 业务对象 184 | * @param thisControlPoint 本控制点。 185 | * @returns 186 | */ 187 | function resetControlPoint(obj,thisControlPoint){ 188 | if(!thisControlPoint && obj.view.controlPoint || thisControlPoint && thisControlPoint===obj.view.controlPoint){ 189 | var controlPoint = obj.view.controlPoint; 190 | var x = obj.view.x +Math.floor((obj.view.width)/2); 191 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。 192 | controlPoint.x = x; 193 | controlPoint.y = y; 194 | } 195 | if(!thisControlPoint && obj.view.controlPoint1 || thisControlPoint && thisControlPoint===obj.view.controlPoint1){ 196 | var controlPoint = obj.view.controlPoint1; 197 | var x = obj.view.x +Math.floor((obj.view.width)/2); 198 | var y = obj.view.y+30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。 199 | controlPoint.x = x; 200 | controlPoint.y = y; 201 | } 202 | //如果控制点缺失要将他补齐 203 | if(obj instanceof Oper ){ 204 | if(!obj.model.activityId && !obj.view.controlPoint){ 205 | var x = obj.view.x +Math.floor((obj.view.width)/2); 206 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。 207 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个 208 | controlPoint.parent = obj;//父对象就是其业务对象。 209 | controlPoint.parentType = 'result'; 210 | obj.view.controlPoint = controlPoint; 211 | } 212 | } 213 | if(obj instanceof Subsequent){ 214 | var fillNum = 0;//需要补充的数量。 215 | if(!obj.model.operationId){ 216 | fillNum++; 217 | } 218 | if(!obj.model.activityId){ 219 | fillNum++; 220 | } 221 | if(obj.view.controlPoint){ 222 | fillNum--; 223 | } 224 | if(obj.view.controlPoint1){ 225 | fillNum--; 226 | } 227 | if(fillNum>0 && !obj.view.controlPoint){ 228 | var x = obj.view.x +Math.floor((obj.view.width)/2); 229 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。 230 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个 231 | controlPoint.parent = obj;//父对象就是其业务对象。 232 | controlPoint.parentType = 'subseq'; 233 | obj.view.controlPoint = controlPoint; 234 | fillNum--; 235 | } 236 | if(fillNum>0 && !obj.view.controlPoint1){ 237 | var x = obj.view.x +Math.floor((obj.view.width)/2); 238 | var y = obj.view.y+30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。 239 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个 240 | controlPoint.parent = obj;//父对象就是其业务对象。 241 | controlPoint.parentType = 'subseq'; 242 | obj.view.controlPoint1 = controlPoint; 243 | fillNum--; 244 | } 245 | 246 | } 247 | } 248 | 249 | /** 250 | * 鼠标拖动控制器,用来调整坐标系 251 | */ 252 | var getMovimgDragCtrl = function(renderCtx){ 253 | var flRender = renderCtx; 254 | function _onDrag(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos){ 255 | renderCtx.moveOriginPoint(afterAbsPos.x-beforeAbsPos.x,afterAbsPos.y-beforeAbsPos.y); 256 | } 257 | return { 258 | /**开始拖动事件*/ 259 | onStartDrag:function (obj){ 260 | //do nothing. 261 | }, 262 | /**结束拖动鼠标事件*/ 263 | onEndDrag:function(obj){ 264 | //do nothing. 265 | }, 266 | /**拖动事件*/ 267 | onDrag:function(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos){ 268 | _onDrag(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos) 269 | }, 270 | /**右击事件*/ 271 | rightClick:function(obj){ 272 | //do nothing. 273 | } 274 | }; 275 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Tang Jun 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /flow_designer/WebContent/example/example1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 10 | 01 11 | 1 12 | 0 13 | 0000 14 | 提交请假申请 15 | 提交请假申请 16 | 0000 17 | 18 | 19 | 105 20 | 36 21 | 28 22 | 401 23 | 124 24 | 25 | 26 | 27 | 28 | 0 29 | 01 30 | 0 31 | 1 32 | 0001 33 | 科长审批 34 | 科长审批 35 | 0001 36 | 37 | 38 | 106 39 | 36 40 | 28 41 | 402 42 | 294 43 | 44 | 45 | 46 | 47 | 0 48 | 01 49 | 0 50 | 0 51 | 0002 52 | 处级领导审批 53 | 处级领导审批 54 | 0002 55 | 56 | 57 | 108 58 | 36 59 | 28 60 | 404 61 | 463 62 | 63 | 64 | 65 | 66 | 0 67 | 01 68 | 0 69 | 0 70 | 0003 71 | 局级领导审批 72 | 局级领导审批 73 | 0003 74 | 75 | 76 | 112 77 | 36 78 | 28 79 | 405 80 | 627 81 | 82 | 83 | 84 | 85 | 0 86 | 01 87 | 0 88 | 0 89 | 0004 90 | 人事部备案 91 | 人事部备案 92 | 0004 93 | 94 | 95 | 122 96 | 36 97 | 28 98 | 633 99 | 699 100 | 101 | 102 | 103 | 104 | 105 | 106 | 0 107 | 1 108 | 00:00:00 109 | 0000 110 | 111 | 112 | 提交 113 | 提交 114 | 000001 115 | 000001 116 | 1 117 | 118 | 119 | 107 120 | 12 121 | 12 122 | 409 123 | 201 124 | null 125 | 126 | 127 | 128 | 129 | 0 130 | 1 131 | 00:00:00 132 | 0001 133 | 134 | 135 | 审批通过 136 | 审批通过 137 | 000101 138 | 1 139 | 000101 140 | 141 | 142 | 109 143 | 12 144 | 12 145 | 526 146 | 374 147 | null 148 | 149 | 150 | 151 | 152 | 0 153 | 1 154 | 00:00:00 155 | 0001 156 | 157 | 158 | 审批驳回 159 | 审批驳回 160 | 000198 161 | 000198 162 | 0 163 | 0 164 | 165 | 166 | 110 167 | 12 168 | 12 169 | 294 170 | 230 171 | null 172 | 173 | 174 | 175 | 176 | 0 177 | 1 178 | 00:00:00 179 | 0001 180 | 181 | 182 | 请假2天以上 183 | 请假2天以上 184 | 000103 185 | 000103 186 | 187 | 188 | 111 189 | 12 190 | 12 191 | 411 192 | 371 193 | null 194 | 195 | 196 | 197 | 198 | 0 199 | 1 200 | 00:00:00 201 | 0002 202 | 203 | 204 | 请假一周以上 205 | 请假一周以上 206 | 000202 207 | 000202 208 | 209 | 210 | 113 211 | 12 212 | 12 213 | 412 214 | 536 215 | null 216 | 217 | 218 | 219 | 220 | 0 221 | 1 222 | 00:00:00 223 | 0002 224 | 225 | 226 | 驳回 227 | 驳回 228 | 000298 229 | 000298 230 | 231 | 232 | 114 233 | 12 234 | 12 235 | 299 236 | 445 237 | null 238 | 239 | 240 | 241 | 242 | 0 243 | 1 244 | 00:00:00 245 | 0002 246 | 247 | 248 | 通过 249 | 通过 250 | 000201 251 | 000201 252 | 0 253 | 254 | 255 | 115 256 | 12 257 | 12 258 | 522 259 | 495 260 | null 261 | 262 | 263 | 264 | 265 | 0 266 | 1 267 | 00:00:00 268 | 0003 269 | 270 | 271 | 驳回 272 | 驳回 273 | 000398 274 | 000398 275 | 276 | 277 | 120 278 | 12 279 | 12 280 | 294 281 | 604 282 | null 283 | 284 | 285 | 286 | 287 | 0 288 | 1 289 | 00:00:00 290 | 0003 291 | 292 | 293 | 通过 294 | 通过 295 | 000301 296 | 000301 297 | 298 | 299 | 121 300 | 12 301 | 12 302 | 520 303 | 676 304 | null 305 | 306 | 307 | 308 | 309 | 0 310 | 1 311 | 00:00:00 312 | 0004 313 | 314 | 315 | 结束 316 | 结束 317 | 000401 318 | 000401 319 | 1 320 | 321 | 322 | 124 323 | 12 324 | 12 325 | 640 326 | 782 327 | null 328 | 329 | 330 | 331 | 332 | 333 | 334 | 0 335 | 0 336 | 1 337 | 338 | 0001 339 | 000001 340 | 341 | 342 | 410 343 | 255 344 | null 345 | null 346 | 12 347 | 12 348 | 116 349 | 350 | 351 | 352 | 353 | 0 354 | 0 355 | 1 356 | 357 | 0002 358 | 000103 359 | 360 | 361 | 412 362 | 422 363 | null 364 | null 365 | 12 366 | 12 367 | 117 368 | 369 | 370 | 371 | 372 | 0 373 | 0 374 | 1 375 | 376 | 0001 377 | 000298 378 | 379 | 380 | 299 381 | 338 382 | null 383 | null 384 | 12 385 | 12 386 | 118 387 | 388 | 389 | 390 | 391 | 0 392 | 0 393 | 1 394 | 395 | 0003 396 | 000202 397 | 398 | 399 | 412 400 | 584 401 | null 402 | null 403 | 12 404 | 12 405 | 119 406 | 407 | 408 | 409 | 410 | 0 411 | 0 412 | 1 413 | 414 | 0000 415 | 000198 416 | 417 | 418 | 294 419 | 178 420 | null 421 | null 422 | 12 423 | 12 424 | 425 | 426 | 427 | 428 | 0 429 | 0 430 | 1 431 | 432 | 0002 433 | 000398 434 | 435 | 436 | 296 437 | 499 438 | null 439 | null 440 | 12 441 | 12 442 | 443 | 444 | 445 | 446 | 0 447 | 0 448 | 1 449 | 450 | 0004 451 | 000201 452 | 453 | 454 | 639 455 | 599 456 | null 457 | null 458 | 12 459 | 12 460 | 461 | 462 | 463 | 464 | 0 465 | 0 466 | 1 467 | 468 | 0004 469 | 000301 470 | 471 | 472 | 576 473 | 691 474 | null 475 | null 476 | 12 477 | 12 478 | 479 | 480 | 481 | 482 | -------------------------------------------------------------------------------- /flow_designer/WebContent/designer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 流程模型管理 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 438 | 439 | 440 |
441 | 442 |
443 | 444 |
445 | 446 | 447 | 448 | 449 |
450 |
451 | 452 | 453 |
454 |
455 | 456 |
457 |
458 |
459 |
460 |
图形库
461 |
462 |
463 | 464 |
任意一人
465 |
466 |
467 | 468 |
多人串行
469 |
470 |
471 | 472 |
多人并行
473 |
474 |
475 | 476 |
结果线
477 |
478 |
479 | 480 |
后续线
481 |
482 |
483 |
484 | 485 |
486 | 487 |
488 |
流程基本信息
489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 |
流程代码
版本号
流程名称
显示名称
流程描述
513 |
514 | 515 |
516 |
活动基本信息
517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 556 | 557 | 558 | 559 | 562 | 563 | 564 |
活动代码
活动名称
显示名称
权限代码
链接地址
排序号
活动说明
活动类型 550 | 555 |
是否可撤回 560 | 561 |
565 |
活动控制信息
566 | 567 | 568 | 569 | 572 | 574 | 575 | 576 | 579 | 582 | 583 | 584 | 587 | 590 | 591 | 592 |
570 | 571 | 573 |
577 | 578 | 580 | 流程必须要有一个开始活动。 581 |
585 | 586 | 588 | 同组触发顺序的其他活动均已完成时,本活动自动完成,并触发下一触发顺序的活动。 589 |
593 |
活动权限范围信息
594 |
595 | 596 | 597 | 598 |
599 | 600 |
601 | 602 | 603 |
604 |
结果基本信息
605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 |
结果代码
结果名称
业务名称
排序号
结果说明
权限代码
633 |
结果控制信息
634 | 635 | 636 | 637 | 638 | 643 | 644 | 645 | 646 | 651 | 652 | 653 |
是否中断 639 |
640 |
撤销本活动引发的所有后续待办任务
641 |
642 |
意见必输 647 |
648 |
用户意见必输
649 |
650 |
654 |
自动完成信息
655 | 656 | 657 | 658 | 659 | 664 | 665 | 666 | 667 | 670 | 671 | 672 | 673 | 679 | 680 | 681 | 682 | 685 | 686 | 687 |
自动完成 660 |
661 |
到期未完成,自动按此结果处理。
662 |
663 |
截至天数 668 | 669 |
截至时刻 674 | 678 |
683 | 684 |
688 |
689 | 690 | 691 |
692 |
后续控制信息
693 | 694 | 695 | 696 | 697 | 700 | 701 | 702 | 703 | 708 | 709 | 710 | 711 | 714 | 715 | 716 | 717 | 720 | 721 | 722 | 723 | 726 | 727 | 728 | 729 | 734 | 735 | 736 |
触发顺序 698 | 699 |
等待活动 704 | 707 |
状态代码 712 | 713 |
状态名称 718 | 719 |
排序号 724 | 725 |
附加活动 730 |
731 |
执行与否不影响其他活动
732 |
733 |
737 |
后续用户对象
738 | 739 | 740 | 741 | 742 | 745 | 746 | 747 | 748 | 753 | 754 | 755 | 756 | 761 | 762 | 763 | 764 | 769 | 770 | 771 | 772 | 777 | 778 | 779 | 780 | 791 | 792 | 793 | 794 | 799 | 800 | 801 |
控制位 743 | 744 |
是否显示 749 |
750 |
显示后续用户对象选择界面
751 |
752 |
是否必选 757 |
758 |
后续用户对象必须选择
759 |
760 |
是否唯一 765 |
766 |
后续用户对象最多选择一人
767 |
768 |
内部用户 773 |
774 |
后续用户对象只能选择同部门人员
775 |
776 |
默认用户 781 | 790 |
指定活动 795 | 798 |
802 |
803 |
804 |
805 |
806 | 807 | 812 | 818 | 825 | 891 | 892 | -------------------------------------------------------------------------------- /flow_designer/WebContent/designer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 流程图编辑器 3 | * 本js程序依赖于以下程序: 4 | * jQuery.js 5 | * dragController.js 6 | */ 7 | /* 8 | * 定义业务对象 9 | */ 10 | /** 11 | * 基类的构造函数 12 | * @param obj 13 | * @returns 14 | */ 15 | var BussinessObj = function(obj){ 16 | this.model={}; 17 | if(obj && obj instanceof Object){ 18 | this.model=obj.model; 19 | console.log("obj.model.displayName:"+obj.model.displayName); 20 | } 21 | this.view={}; 22 | if(obj && obj instanceof Object && obj.view){ 23 | this.view=obj.view; 24 | } 25 | } 26 | 27 | /** 28 | * 子类,Activity 29 | */ 30 | var Act = function(obj){ 31 | var defaultModel = { 32 | "listNo":0,/*排序号*/ 33 | "activityType":'01', 34 | "activityBz":'0', 35 | "authority":'0', 36 | "canWithdraw":'0' 37 | } 38 | obj.model = $.extend(defaultModel,obj.model); 39 | BussinessObj.call(this,obj); 40 | }; 41 | Act.prototype = new BussinessObj(); 42 | 43 | /** 44 | * 子类,操作选项 45 | */ 46 | var Oper = function(obj){ 47 | var defaultModel = { 48 | "listNo":0,/*排序号*/ 49 | "deadlineType":'1', 50 | "deadlineTime":'00:00:00', 51 | "resultFlag":'0', 52 | "mustHaveOpinion":'0', 53 | "autoFinish":'0' 54 | } 55 | obj.model = $.extend(defaultModel,obj.model); 56 | BussinessObj.call(this,obj); 57 | if(!obj.model.activityId){ 58 | //在业务对象的上方(30个像素处)增加一个控制点。(控制点以图形的中心为准) 59 | var x = this.view.x +Math.floor((icons['oper'].width)/2); 60 | var heightOfMouse = icons['mouse'].height;//鼠标图形的高度 61 | var y = this.view.y-30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。 62 | var controlPoint = new ControlPoint(x,y); 63 | controlPoint.parent = this;//父对象就是其业务对象。 64 | controlPoint.parentType = 'result'; 65 | this.view.controlPoint = controlPoint; 66 | } 67 | }; 68 | Oper.prototype = new BussinessObj(); 69 | 70 | /** 71 | * 子类,后续线 72 | */ 73 | var Subsequent = function(obj){ 74 | var defaultModel = { 75 | "sortNumber":0,/*排序号*/ 76 | "sequence":'0', 77 | "postDisplay":'1', 78 | "postDefault":'', 79 | "inessential":'0', 80 | "postDisplay":'0', 81 | "postMustHave":'0', 82 | "postMustOne":'0', 83 | "postSameDept":'0' 84 | } 85 | obj.model = $.extend(defaultModel,obj.model); 86 | BussinessObj.call(this,obj); 87 | var numOfControlPoint = 0;//控制点数量 88 | if(!obj.model.activityId){ 89 | numOfControlPoint++; 90 | } 91 | if(!obj.model.operationId){ 92 | numOfControlPoint++; 93 | } 94 | //有两个控制点,一个是controlPoint,一个是controlPoint1 95 | if(numOfControlPoint>=1){ 96 | //在业务对象的上方(30个像素处)增加一个控制点。(控制点以图形的中心为准) 97 | var x = this.view.x +Math.floor((icons['subseq'].width)/2); 98 | var heightOfMouse = icons['mouse'].height;//鼠标图形的高度 99 | var y = this.view.y-30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。 100 | var controlPoint = new ControlPoint(x,y); 101 | controlPoint.parent = this;//父对象就是其业务对象。 102 | controlPoint.parentType = 'result'; 103 | this.view.controlPoint=controlPoint; 104 | } 105 | if(numOfControlPoint>=2){ 106 | //在业务对象的下方(30个像素处)增加一个控制点。 107 | var x = this.view.x +Math.floor((icons['subseq'].width)/2); 108 | var y = this.view.y+30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。 109 | var controlPoint = new ControlPoint(x,y); 110 | controlPoint.parent = this;//父对象就是其业务对象。 111 | controlPoint.parentType = 'mouse'; 112 | this.view.controlPoint1=controlPoint; 113 | } 114 | } 115 | Subsequent.prototype = new BussinessObj(); 116 | 117 | /** 118 | * 流程基本信息 119 | */ 120 | var FlowInfo =function(obj){ 121 | var defaultModel = { 122 | "flowId":0,/*流程模型的编号*/ 123 | "version":'1.0',/*流程模型的版本号*/ 124 | "flowName":'',/*流程模型的名称*/ 125 | "displayName":'', 126 | "description":'' 127 | }; 128 | if(!obj){ 129 | obj = {}; 130 | } 131 | obj.model = $.extend(defaultModel,obj.model); 132 | if(!obj.view){ 133 | obj.view = {width:84,height:60}; 134 | } 135 | BussinessObj.call(this,obj); 136 | } 137 | 138 | /** 139 | * 一个坐标点 140 | */ 141 | var Point = function(x,y){ 142 | this.x = 0; 143 | this.y = 0; 144 | if(x) 145 | this.x=x; 146 | if(y) 147 | this.y=y; 148 | } 149 | /** 150 | * 控制点(业务对象上可以被鼠标拖动的点) 151 | */ 152 | var ControlPoint = function(x,y){ 153 | Point.call(this,x,y); 154 | } 155 | ControlPoint.prototype = new Point(); 156 | 157 | /** 158 | * 绘图过程中要使用到的图片(图标) 159 | */ 160 | var icons = (function(){ 161 | //活动图片. 162 | var actImg = new Image(); 163 | actImg.src='imgs/design/anyone.gif'; 164 | actImg.width = 28;//这里未必是图片真实的宽度,因图片上有可能有空白的边。 165 | actImg.height = 36;//这里未必是图片真实的高度,因图片上有可能有空白的边。 166 | //开始活动图片. 167 | var actStartImg = new Image(); 168 | actStartImg.src='imgs/design/anyone_start.gif'; 169 | actStartImg.width = 28; 170 | actStartImg.height = 36; 171 | //自动完成活动图片. 172 | var actAutoImg = new Image(); 173 | actAutoImg.src='imgs/design/anyone_auto.gif'; 174 | actAutoImg.width = 28; 175 | actAutoImg.height = 36; 176 | //多人并行 177 | var actPiallImg = new Image(); 178 | actPiallImg.src='imgs/design/paiallel.gif'; 179 | actPiallImg.width = 28; 180 | actPiallImg.height = 36; 181 | //多人串行 182 | var actSeqImg = new Image(); 183 | actSeqImg.src='imgs/design/sequence.gif'; 184 | actSeqImg.width = 28; 185 | actSeqImg.height = 36; 186 | //图片结果图片 187 | var operImg = new Image(); 188 | operImg.src='imgs/design/result.gif'; 189 | operImg.width = 12; 190 | operImg.height = 12; 191 | //自动完成的结果 192 | var operAutoImg = new Image(); 193 | operAutoImg.src= 'imgs/design/result_auto.gif'; 194 | operAutoImg.width = 12; 195 | operAutoImg.height = 12; 196 | //中断的结果 197 | var operBreakImg = new Image(); 198 | operBreakImg.src= 'imgs/design/result_break.gif'; 199 | operBreakImg.width = 12; 200 | operBreakImg.height = 12; 201 | //控制点图片 202 | var mouseImg = new Image(); 203 | mouseImg.src='imgs/design/mouse_add.png'; 204 | mouseImg.width = 16; 205 | mouseImg.height = 16; 206 | //后续线图片(没有图片,是直接在画布上画的圆圈) 207 | var subseqImg = new Image(); 208 | subseqImg.width = 12; 209 | subseqImg.height = 12; 210 | return { 211 | "act":actImg, 212 | "act_start":actStartImg, 213 | "act_auto":actAutoImg, 214 | "act_piall":actPiallImg, 215 | "act_seq":actSeqImg, 216 | "oper":operImg, 217 | "oper_auto":operAutoImg, 218 | "oper_break":operBreakImg, 219 | "mouse":mouseImg, 220 | "subseq":subseqImg 221 | } 222 | 223 | 224 | })(); 225 | 226 | /** 227 | * 图形绘制器 228 | * @param canvasId 页面上的画布元素 229 | * @options 配置项. 230 | * @returns 231 | */ 232 | function FlRenderer(canvasId,options){ 233 | options = options || {}; 234 | 235 | /** 236 | * 模型 237 | */ 238 | var flowModle = { 239 | flowInfo:new FlowInfo({}), 240 | activities:[],/*活动*/ 241 | operations:[],/*操作结果*/ 242 | subsequents:[] /*操作结果*/ 243 | }; 244 | 245 | var originPoint = {x:0,y:0};//坐标系原点在画布上的位置 246 | 247 | /* 248 | * 选中的对象 249 | */ 250 | var selected = []; 251 | var redMarked = null;//标红的对象 252 | 253 | var c = null;//画布元素. 254 | 255 | var maxDisplayindex = 0 ;//displayindex从0开始编号 256 | 257 | /**拖动模式:normal-正常模式,moving-移动模式(调整坐标系时) */ 258 | //var dragMode = 'normal'; 259 | 260 | c = document.getElementById(canvasId); 261 | var cxt = c.getContext("2d"); //绘图上下文. 262 | 263 | /** 264 | * 选中一个业务对象后需要触发的事件 265 | */ 266 | var onSelect = function(bizObj){/*空函数*/}; 267 | 268 | if(typeof(options.onSelect)=='function'){ 269 | onSelect = options.onSelect; 270 | } 271 | 272 | //init(); 273 | drawAll(cxt); 274 | 275 | var isMouseDown = false;//鼠标左键是否按下 276 | //鼠标拖动控制器,暂时不设定,等后面再设定. 277 | var defualtDragCtrl = null;//getDefaultDragCtrl(this); 278 | var dragCtrl = null;//defualtDragCtrl; 279 | 280 | //监听事件onclick 281 | $(c).click(function(){ 282 | //看看鼠标落在哪个对象上。 283 | selected = []; 284 | //先看看有没有选择流程的基本信息 285 | var x = event.pageX-c.offsetLeft; 286 | var y = event.pageY-c.offsetTop; 287 | flowInfoView = flowModle.flowInfo.view; 288 | if(0<=x && x<=flowInfoView.width && 0<=y && y<=flowInfoView.height){ 289 | selected.push(flowModle.flowInfo); 290 | }else{ 291 | //获取鼠标的坐标(相对于画布的位置)。 292 | var cursorPos = getCursorPos(event,c); 293 | x = cursorPos.x; 294 | y = cursorPos.y; 295 | //console.log("x:"+x+" y:"+y ); 296 | var obj = selectObj(x,y); 297 | if(obj && obj instanceof BussinessObj){ 298 | selected.push(obj); 299 | } 300 | } 301 | drawAll(cxt); 302 | if(selected.length>0){ 303 | //TODO obj 应当深拷贝后再传出去的。 304 | onSelect(selected[selected.length-1]); 305 | }else{ 306 | onSelect(null); 307 | } 308 | }); 309 | 310 | //处理右键 311 | //先把他禁用掉 312 | $(c).bind("contextmenu", function(){ 313 | return false; 314 | }); 315 | //再处理事件 316 | $(c).mouseup(function(e) { 317 | if(event.button == 2){//右键为2 318 | if(typeof(dragCtrl.rightClick)=='function'){ 319 | var cursorPos = getCursorPos(event,c); 320 | var obj = selectObj(cursorPos.x,cursorPos.y); 321 | if(obj instanceof BussinessObj){ 322 | dragCtrl.rightClick(obj); 323 | } 324 | 325 | } 326 | } 327 | }); 328 | 329 | //监听鼠标移动事件 330 | $(c).mousemove(function(){ 331 | if(!isMouseDown) 332 | return; 333 | //获取鼠标的坐标(相对于原点的位置)。 334 | var cursorPos = getCursorPos(event,c); 335 | //鼠标当前位置,(相对于画布的位置)。 336 | var absPos = getCursorAbsPos(event,c); 337 | //console.log("x:"+cursorPos.x+" y:"+cursorPos.y ); 338 | if(preDragPos==null || preDragAbsPos == null){ 339 | preDragPos = cursorPos; 340 | preDragAbsPos = absPos; 341 | } 342 | thisDragePos = cursorPos; 343 | thisAbsPos = absPos; 344 | dragCtrl.onDrag(dragedObj,preDragPos,thisDragePos,preDragAbsPos,thisAbsPos); 345 | drawAll(cxt); 346 | preDragPos = thisDragePos; 347 | preDragAbsPos = thisAbsPos; 348 | }); 349 | 350 | var dragedObj = null;//被拖动的对象 351 | var preDragPos = null;//上次拖动的坐标(相对于原点) 352 | var preDragAbsPos = null;//上次拖动的坐标(相对于画布) 353 | 354 | //监听鼠标左键按下事件 355 | $(c).mousedown(function(){ 356 | if(event.button == 0){//为0表示左键 357 | isMouseDown = true; 358 | //获取鼠标的当前位置 359 | var cursorPos = getCursorPos(event,c); 360 | var absPos = getCursorAbsPos(event,c); 361 | //看看有没有controlPoint被选中 362 | var obj = selectObj(cursorPos.x,cursorPos.y); 363 | if(obj){ 364 | //console.log("onStartDrag obj:"+obj); 365 | dragedObj = obj; 366 | preDragPos = cursorPos;//getCursorPos(event,c); 367 | preDragAbsPos = absPos; 368 | dragCtrl.onStartDrag(obj); 369 | } 370 | } 371 | }); 372 | //监听鼠标左键释放事件 373 | $(c).mouseup(function(){ 374 | if(event.button == 0){ 375 | isMouseDown = false; 376 | //有可能是拖动结束 377 | if(preDragPos!=null){ 378 | //拖动结束 379 | dragCtrl.onEndDrag(dragedObj); 380 | preDragPos = null; 381 | preDragAbsPos = null; 382 | dragedObj = null; 383 | } 384 | redMarked = null; 385 | } 386 | }); 387 | 388 | /**清空选中*/ 389 | function _clearSelected(){ 390 | selected=[]; 391 | //需要触发onSelect事件,放在另一个线程中执行 392 | setTimeout(function(){onSelect(null);},0); 393 | } 394 | 395 | /** 396 | * 根据鼠标所选中的位置,判断哪个控件被选中了。 397 | */ 398 | function selectObj(x,y){ 399 | for(var i in flowModle.activities){ 400 | view = flowModle.activities[i].view; 401 | //console.log("view.x:"+view.x+" view.y:"+view.y + " x:"+x+" y:"+y ); 402 | if(view.xy1){ 572 | y-=500; 573 | } 574 | y+=500 575 | while(y<=y2){ 576 | if(yx1){ 592 | x-=500; 593 | } 594 | x+=500 595 | while(x<=x2){ 596 | if(x=3){//优先级大于2,则用双点划线 672 | cxt.setLineDash([10,4,2,4,2,4]); 673 | } 674 | 675 | if(subseq.model.activityId){//如果关联了一个活动 676 | //console.log("subseq.model.activityId:"+subseq.model.activityId); 677 | //查找对应的活动 678 | var act = selectActByActId(subseq.model.activityId); 679 | //绘制从圆圈到活动的线条。 680 | if(act){ 681 | //act.view 682 | cxt.beginPath(); 683 | cxt.lineWidth=0.5; 684 | cxt.strokeStyle='black'; 685 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5);//由于像素精度问题所以每个坐标都要减0.5个像素 686 | cxt.lineTo(act.view.x+act.view.width/2-0.5,act.view.y+act.view.height/2-0.5); 687 | cxt.stroke(); 688 | } 689 | } 690 | if(subseq.model.operationId){//如果关联了一个结果 691 | //console.log("subseq.model.activityId:"+subseq.model.operationId); 692 | //查找对应的结果 693 | var oper = selectOperByOperId(subseq.model.operationId); 694 | //绘制从圆圈到活动的结果。 695 | if(oper){ 696 | //act.view 697 | cxt.beginPath(); 698 | cxt.lineWidth=0.5; 699 | cxt.strokeStyle='black'; 700 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5); 701 | cxt.lineTo(oper.view.x+oper.view.width/2-0.5,oper.view.y+oper.view.height/2-0.5); 702 | cxt.stroke(); 703 | } 704 | 705 | } 706 | if(subseq.view.controlPoint){//存在控制点 707 | var controlPoint = subseq.view.controlPoint; 708 | //绘制连线到控制点 709 | cxt.beginPath(); 710 | cxt.lineWidth=0.5; 711 | cxt.strokeStyle='black'; 712 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5); 713 | cxt.lineTo(controlPoint.x-0.5,controlPoint.y-0.5); 714 | cxt.stroke(); 715 | } 716 | if(subseq.view.controlPoint1){//存在控制点 717 | var controlPoint = subseq.view.controlPoint1; 718 | //绘制连线到控制点 719 | cxt.beginPath(); 720 | cxt.lineWidth=0.5; 721 | cxt.strokeStyle='black'; 722 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5); 723 | cxt.lineTo(controlPoint.x-0.5,controlPoint.y-0.5,15);//15每一行的高度(字体高12个像素,在加上3个像素的行距。) 724 | cxt.stroke(); 725 | } 726 | cxt.setLineDash([]);//绘制完后还原成实线。 727 | } 728 | 729 | /** 730 | * 绘制流程基本信息 731 | */ 732 | function drawFlowInfo(cxt,obj){ 733 | if(!(obj instanceof FlowInfo)){ 734 | return ;//本函数仅处理FLowInfo 735 | } 736 | cxt.beginPath(); 737 | cxt.lineWidth=1; 738 | cxt.fillStyle = '#bdf'; 739 | cxt.strokeStyle='grey'; 740 | cxt.rect(0.5,0.5,obj.view.width+0.5,obj.view.height+0.5); 741 | cxt.fill(); 742 | cxt.stroke(); 743 | //画文字 744 | cxt.fillStyle = 'black'; 745 | cxt.font = "bold 14px songti"; 746 | console.log(obj.model.displayName); 747 | if(obj.model.displayName){//不至于在页面上显示undefind 748 | cxt.textAlign="center"; 749 | cxt.textBaseline="middle"; 750 | _fillTextInRect(cxt,obj.model.displayName, 0,0,obj.view.width, obj.view.height);//12是字体的高度 751 | cxt.textAlign="start";//恢复成默认值 752 | cxt.textBaseline="alphabetic";//恢复成默认值 753 | } 754 | //是否被选中 755 | if(selected.indexOf(obj)>=0){ 756 | //选中则要绘制一下 757 | cxt.beginPath(); 758 | cxt.lineWidth=1; 759 | cxt.strokeStyle='green'; 760 | cxt.rect(0,0,obj.view.width+1,obj.view.height+1); 761 | cxt.stroke(); 762 | } 763 | } 764 | 765 | function _fillTextInRect(cxt,text,x1,y1,x2,y2,lineH){ 766 | var dimension = cxt.measureText(text); 767 | var allLength = dimension.width; 768 | if(allLength<(x2-x1)){ 769 | //单行文本 770 | cxt.fillText(text, (x1+x2)/2, (y1+y2)/2); 771 | return 772 | } 773 | //否则字符超超长需要换行 774 | var widthPorChar = Math.ceil(allLength/text.length);//每个字符的宽度. 775 | var lineH = lineH||14;//每一行的高度() 776 | var charsPorLine = Math.floor(((x2-x1)/widthPorChar));//每行能容纳的文字数. 777 | //先计算一下总共能容纳多少文字 778 | var charCapacity = Math.floor((y2-y1)/lineH)*charsPorLine; 779 | if(text.lengt>charCapacity){ 780 | text = text.substr(0,charCapacity-2)+'...'; 781 | } 782 | //文字换行切割 783 | var texts = []; 784 | while(text.length>charsPorLine){ 785 | texts.push(text.substr(0,charsPorLine)); 786 | text = text.substr(charsPorLine); 787 | } 788 | texts.push(text); 789 | var lines = texts.length;//行数 790 | console.log("lines:"+lines); 791 | var startY = (y1+y2)/2; 792 | if(lines%2==1){//奇数行 793 | startY -= lineH*Math.floor(lines/2); 794 | }else{//偶数行 795 | startY -= lineH*(Math.floor(lines/2)-0.5); 796 | } 797 | var y=startY; 798 | console.log("yyyyyy:"+y); 799 | for(var i in texts){ 800 | cxt.fillText(texts[i], (x1+x2)/2, y); 801 | y+=lineH; 802 | console.log("yyyyyy:"+y); 803 | } 804 | 805 | } 806 | 807 | /** 808 | * 绘制一个业务对象 809 | */ 810 | function drawBizObj(cxt,obj){ 811 | if(obj instanceof Act){ 812 | drawActivity(cxt,obj); 813 | }else if(obj instanceof Oper){ 814 | drawOperation(cxt,obj); 815 | }else if(obj instanceof Subsequent){ 816 | drawSubsequent(cxt,obj); 817 | } 818 | } 819 | 820 | /** 821 | * 绘制一个活动 822 | */ 823 | function drawActivity(cxt,act){ 824 | //console.log("act.model:"+act.model); 825 | //绘制活动的名称 826 | //console.log("act.model.displayName:"+act.model.displayName); 827 | if(act.model.displayName){ 828 | cxt.fillStyle = 'black'; 829 | cxt.font = "bold 14px songti"; 830 | var textLeft = act.view.x+(act.view.width-act.model.displayName.length*14)/2 //14是字体的宽度。 831 | //console.log("act.model.displayName:"+act.model.displayName+" textLeft:"+textLeft+" act.view.y-8"+(act.view.y-8)); 832 | cxt.fillText(act.model.displayName,textLeft,act.view.y-8);//文字写在图像上方8个像素点处。 833 | } 834 | var icon = icons['act']; 835 | if(act.model.activityBz=='1'){ 836 | icon = icons['act_start']; 837 | }else if(act.model.activityBz=='2'){ 838 | icon = icons['act_auto']; 839 | }else if(act.model.activityType=='03'){ 840 | icon = icons['act_piall']; 841 | }else if(act.model.activityType=='02'){ 842 | icon = icons['act_seq']; 843 | } 844 | cxt.drawImage(icon,act.view.x,act.view.y); 845 | } 846 | /** 847 | * 绘制一个结果线 848 | */ 849 | function drawOperation(cxt,oper){ 850 | var view = oper.view; 851 | var icon = icons['oper']; 852 | if(oper.model.resultFlag=='1'){ 853 | icon = icons['oper_break']; 854 | }else if(oper.model.autoFinish=='1'){ 855 | icon = icons['oper_auto']; 856 | } 857 | cxt.drawImage(icon,oper.view.x,oper.view.y); 858 | //如果关联了一个活动 859 | //console.log("oper.model.activityId:"+oper.model.activityId); 860 | if(oper.model.activityId){ 861 | console.log("oper.model.activityId:"+oper.model.activityId); 862 | //do nothing. 863 | }else if(oper.view.controlPoint){//存在控制点 864 | //在控制点处绘制一个鼠标。 865 | var mouseLeft = oper.view.controlPoint.x - Math.floor(icons['mouse'].width/2); 866 | var mouseTop = oper.view.controlPoint.y - Math.floor(icons['mouse'].height/2); 867 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop); 868 | } 869 | cxt.fillStyle = 'black'; 870 | cxt.font = "12px songti"; 871 | var textLeft = oper.view.x+Math.floor((oper.view.width-oper.model.displayName.length*12)/2); //12是字体的宽度 872 | cxt.fillText(oper.model.displayName,textLeft,oper.view.y+oper.view.height+12);//12是字体的高度 873 | } 874 | /** 875 | * 绘制一个后续线. 876 | */ 877 | function drawSubsequent(ctx,subseq){ 878 | //后续线的中心点上绘制一个圆圈 879 | //先计算圆形的中心 880 | var x = subseq.view.x + Math.floor(subseq.view.width/2); 881 | var y = subseq.view.y + Math.floor(subseq.view.height/2); 882 | //半径是宽度的1/4 883 | var r = Math.floor(subseq.view.width/4); 884 | //console.log('arc: x:'+x+" y:"+y+ " r:"+r); 885 | //开始绘制 886 | ctx.beginPath(); 887 | //设置弧线的颜色为灰色 888 | ctx.lineWidth="0.5"; 889 | ctx.strokeStyle = "black"; 890 | ctx.arc(x, y, r, 0, 2*Math.PI); 891 | ctx.closePath(); 892 | ctx.fillStyle = "white"; 893 | ctx.fill(); 894 | ctx.stroke(); 895 | //绘制控制点 896 | var controlPoint = subseq.view.controlPoint; 897 | if(controlPoint){ 898 | var mouseLeft = controlPoint.x - Math.floor(icons['mouse'].width/2); 899 | var mouseTop = controlPoint.y - Math.floor(icons['mouse'].height/2); 900 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop); 901 | } 902 | var controlPoint = subseq.view.controlPoint1; 903 | if(controlPoint){ 904 | var mouseLeft = controlPoint.x - Math.floor(icons['mouse'].width/2); 905 | var mouseTop = controlPoint.y - Math.floor(icons['mouse'].height/2); 906 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop); 907 | } 908 | } 909 | /** 910 | * 绘制选中的元素 911 | */ 912 | function drawSelect(ctx){ 913 | for(var i in selected){ 914 | var view = selected[i].view; 915 | if(selected[i] instanceof FlowInfo){ 916 | continue;//FlowInfo 另行处理 917 | } 918 | //console.log("draw selected."); 919 | ctx.beginPath(); 920 | ctx.lineWidth="1"; 921 | ctx.strokeStyle="green"; 922 | ctx.rect(view.x,view.y,view.width,view.height); 923 | ctx.stroke(); 924 | } 925 | } 926 | 927 | function drawReadMarked(ctx){ 928 | if(redMarked){ 929 | var view = redMarked.view; 930 | //console.log("draw red mark."); 931 | ctx.beginPath(); 932 | ctx.lineWidth="1"; 933 | ctx.strokeStyle="red"; 934 | ctx.rect(view.x,view.y,view.width,view.height); 935 | ctx.stroke(); 936 | } 937 | } 938 | 939 | /** 940 | * 获取鼠标的位置,考虑坐标系 941 | * @param event 事件 942 | * @param canvase 元素 943 | * @returns {x:x,y:y} 944 | */ 945 | function getCursorPos(event,c){ 946 | var x = event.pageX-c.offsetLeft; 947 | var y = event.pageY-c.offsetTop; 948 | //按原点位置调整坐标系 949 | x+=originPoint.x; 950 | y+=originPoint.y; 951 | return {x:x,y:y}; 952 | } 953 | 954 | /**获取鼠标的位置,不考虑坐标系*/ 955 | function getCursorAbsPos(event,c){ 956 | var x = event.pageX-c.offsetLeft; 957 | var y = event.pageY-c.offsetTop; 958 | return {x:x,y:y}; 959 | } 960 | 961 | /** 962 | * 获取整个图形的边界 963 | */ 964 | function getBound(){ 965 | var maxX = null; 966 | var minX = null; 967 | var maxY = null; 968 | var minY = null; 969 | 970 | for(var i in flowModle.activities){ 971 | var x=flowModle.activities[i].view.x; 972 | var y=flowModle.activities[i].view.y; 973 | if(maxX==null){ 974 | maxX = x; 975 | }else{ 976 | maxX = Math.max(maxX,x); 977 | } 978 | if(minX==null){ 979 | minX = x; 980 | }else{ 981 | minX = Math.min(minX,x); 982 | } 983 | if(maxY==null){ 984 | maxY = y; 985 | }else{ 986 | maxY = Math.max(maxY,y); 987 | } 988 | if(minY==null){ 989 | minY = y; 990 | }else{ 991 | minY = Math.min(minY,y); 992 | } 993 | } 994 | 995 | for(var i in flowModle.operations){ 996 | var x=flowModle.operations[i].view.x; 997 | var y=flowModle.operations[i].view.y; 998 | if(maxX==null){ 999 | maxX = x; 1000 | }else{ 1001 | maxX = Math.max(maxX,x); 1002 | } 1003 | if(minX==null){ 1004 | minX = x; 1005 | }else{ 1006 | minX = Math.min(minX,x); 1007 | } 1008 | if(maxY==null){ 1009 | maxY = y; 1010 | }else{ 1011 | maxY = Math.max(maxY,y); 1012 | } 1013 | if(minY==null){ 1014 | minY = y; 1015 | }else{ 1016 | minY = Math.min(minY,y); 1017 | } 1018 | } 1019 | 1020 | for(var i in flowModle.subsequents){ 1021 | var x=flowModle.subsequents[i].view.x; 1022 | var y=flowModle.subsequents[i].view.y; 1023 | if(maxX==null){ 1024 | maxX = x; 1025 | }else{ 1026 | maxX = Math.max(maxX,x); 1027 | } 1028 | if(minX==null){ 1029 | minX = x; 1030 | }else{ 1031 | minX = Math.min(minX,x); 1032 | } 1033 | if(maxY==null){ 1034 | maxY = y; 1035 | }else{ 1036 | maxY = Math.max(maxY,y); 1037 | } 1038 | if(minY==null){ 1039 | minY = y; 1040 | }else{ 1041 | minY = Math.min(minY,y); 1042 | } 1043 | } 1044 | 1045 | if(maxX==null || minX==null || maxY==null || minY==null ){ 1046 | //只要有一个为空则无需处理坐标系 1047 | return; 1048 | } 1049 | return {maxX:maxX,minX:minX,maxY:maxY,minY:minY}; 1050 | } 1051 | 1052 | /** 1053 | * 使整个流程图居中 1054 | */ 1055 | function _makeCenter(){ 1056 | var bound = getBound(); 1057 | var maxX = bound.maxX; 1058 | var minX = bound.minX; 1059 | var maxY = bound.maxY; 1060 | var minY = bound.minY; 1061 | 1062 | //获得了模型的中心点 1063 | var centerX = (minX+maxX)/2; 1064 | var centerY = (minY+maxY)/2; 1065 | console.log("centerX:"+centerX); 1066 | console.log("centerY:"+centerY); 1067 | console.log("c.height:"+c.height); 1068 | console.log("c.height/2:"+(c.height/2)); 1069 | //新的原点 1070 | var x = Math.floor(centerX-c.width/2+0.5);//0.5的目的是为了四舍五入 1071 | var y = Math.floor(centerY-c.height/2+0.5); 1072 | console.log("x:"+x); 1073 | console.log("y:"+y); 1074 | originPoint.x=x; 1075 | originPoint.y=y; 1076 | drawAll(cxt); 1077 | } 1078 | 1079 | /**当业务对象的属性发生变化时要处理的事情 */ 1080 | function _onValueChange(obj,prop,beforValue,value){ 1081 | if(obj instanceof Act){ 1082 | if(prop=='activityId' && beforValue){ 1083 | obj.model.baseId = value; 1084 | var opers = selectOpersByActId(beforValue); 1085 | for(var i in opers){ 1086 | opers[i].model.activityId = value; 1087 | //如果activityId被改成空了就要把控制点恢复 1088 | if(!value){ 1089 | resetControlPoint(opers[i]); 1090 | } 1091 | } 1092 | var subseqs = selectSubseqByActId(beforValue); 1093 | for(var i in subseqs){ 1094 | subseqs[i].model.activityId = value; 1095 | //如果activityId被改成空了就要把控制点恢复 1096 | if(!value){ 1097 | resetControlPoint(subseqs[i]); 1098 | } 1099 | } 1100 | } 1101 | }else if(obj instanceof Oper){ 1102 | if(prop=='operationId' && beforValue){ 1103 | obj.model.baseId = value; 1104 | var subseqs = selectSubseqByOperId(beforValue); 1105 | for(var i in subseqs){ 1106 | subseqs[i].model.operationId = value; 1107 | //如果operationId被改成空了就要把控制点恢复 1108 | if(!value){ 1109 | var controlPoint = new ControlPoint(0,0);//坐标先随便设一个 1110 | controlPoint.parent = subseqs[i];//父对象就是其业务对象。 1111 | controlPoint.parentType = 'subseq'; 1112 | if(!subseqs[i].view.controlPoint){ 1113 | subseqs[i].view.controlPoint = controlPoint; 1114 | }else if(!subseqs[i].view.controlPoint1){ 1115 | subseqs[i].view.controlPoint1 = controlPoint; 1116 | } 1117 | resetControlPoint(subseqs[i]); 1118 | } 1119 | } 1120 | } 1121 | } 1122 | } 1123 | 1124 | /**(级联)删除一个业务对象*/ 1125 | function _deleteObj(obj){ 1126 | if(obj instanceof Act ){ 1127 | _deleteAct(obj); 1128 | }else if(obj instanceof Oper){ 1129 | _deleteOper(obj) 1130 | }else if(obj instanceof Subsequent){ 1131 | _deleteSubseq(obj) 1132 | } 1133 | } 1134 | 1135 | /**(级联)删除一个业务对象*/ 1136 | function _deleteAct(act){ 1137 | var index = flowModle.activities.indexOf(act); 1138 | if(index>=0){ 1139 | flowModle.activities.splice(index,1); 1140 | } 1141 | //查一下有没有子对象,有则把它删除掉. 1142 | if(act.model.activityId){ 1143 | var opers = selectOpersByActId(act.model.activityId); 1144 | for(var i in opers){ 1145 | _deleteOper(opers[i]); 1146 | } 1147 | var subseqs = selectSubseqByActId(act.model.activityId); 1148 | for(var i in subseqs){ 1149 | _deleteSubseq(subseqs[i]); 1150 | } 1151 | } 1152 | } 1153 | 1154 | /**(级联)删除一个业务对象*/ 1155 | function _deleteOper(oper){ 1156 | var index = flowModle.operations.indexOf(oper); 1157 | if(index>=0){ 1158 | flowModle.operations.splice(index,1); 1159 | } 1160 | //查一下有没有子对象,有则把它删除掉. 1161 | if(oper.model.operationId){ 1162 | var subseqs = selectSubseqByOperId(oper.model.operationId); 1163 | for(var i in subseqs){ 1164 | _deleteSubseq(subseqs[i]); 1165 | } 1166 | } 1167 | } 1168 | 1169 | /**删除一个业务对象*/ 1170 | function _deleteSubseq(subseq){ 1171 | var index = flowModle.subsequents.indexOf(subseq); 1172 | if(index>=0){ 1173 | flowModle.subsequents.splice(index,1); 1174 | } 1175 | } 1176 | 1177 | /**某字段是否存在重复*/ 1178 | function _isRepeate(obj,prop,value){ 1179 | if(obj instanceof Act){ 1180 | for(var i in flowModle.activities){ 1181 | var another =flowModle.activities[i]; 1182 | if(another===obj){ 1183 | continue; 1184 | } 1185 | var model = another.model; 1186 | if(model[prop]==value){ 1187 | return true; 1188 | } 1189 | } 1190 | }else if(obj instanceof Oper){ 1191 | for(var i in flowModle.operations){ 1192 | var another =flowModle.operations[i]; 1193 | if(another===obj){ 1194 | continue; 1195 | } 1196 | var model = another.model; 1197 | if(model[prop]==value){ 1198 | return true; 1199 | } 1200 | } 1201 | } 1202 | return false; 1203 | } 1204 | 1205 | /**把整个流程图转成一个图片,base64方式输出*/ 1206 | function _getImgData(){ 1207 | //记录下当前的画布大小,坐标系等。 1208 | var orgSize = {width:c.width,height:c.height} ; 1209 | var orgOPoint = {x:originPoint.x,y:originPoint.y}; 1210 | //调整画布大小 1211 | var bound = getBound(); 1212 | c.width=(bound.maxX-bound.minX+100)>orgSize.width?(bound.maxX-bound.minX+100):orgSize.width;//100是指留100个像素的空白边 1213 | c.height=(bound.maxY-bound.minY+100)>orgSize.height?(bound.maxY-bound.minY+100):orgSize.height;//100是指留100个像素的空白边 1214 | //居中显示 1215 | _makeCenter(); 1216 | //把流程图转成base64. 1217 | var imgData = c.toDataURL("image/png"); 1218 | console.log("imgData:"+imgData); 1219 | //还原画布大小,坐标系等。 1220 | c.width = orgSize.width; 1221 | c.height = orgSize.height; 1222 | originPoint.x = orgOPoint.x; 1223 | originPoint.y = orgOPoint.y; 1224 | //重新绘制 1225 | drawAll(cxt); 1226 | 1227 | return imgData; 1228 | } 1229 | 1230 | 1231 | //暴露出去一个对象 1232 | var exportObj = { 1233 | /**加载一个模型*/ 1234 | loadModel:function(modelJson){ 1235 | //先清空模型 1236 | flowModle.flowInfo={}; 1237 | flowModle.activities = []; 1238 | flowModle.operations = []; 1239 | flowModle.subsequents = []; 1240 | _clearSelected(); 1241 | //基本信息 1242 | console.log("displayName:"+modelJson.flowInfo.displayName); 1243 | flowModle.flowInfo = new FlowInfo(modelJson.flowInfo); 1244 | flowModle.flowInfo.view.width = 84; 1245 | flowModle.flowInfo.view.height = 60; 1246 | for(var i in modelJson.activities){ 1247 | var act = new Act(modelJson.activities[i]); 1248 | if(act.view.displayindex){ 1249 | maxDisplayindex = Math.max(maxDisplayindex,act.view.displayindex); 1250 | }else{ 1251 | act.view.displayindex = ++maxDisplayindex; 1252 | } 1253 | //设置宽度和高度. 1254 | act.view.width = icons['act'].width; 1255 | act.view.height = icons['act'].height; 1256 | flowModle.activities.push(act); 1257 | console.log('加载了一个Act'); 1258 | } 1259 | for(var i in modelJson.operations){ 1260 | var oper = new Oper(modelJson.operations[i]); 1261 | if(oper.view.displayindex){ 1262 | maxDisplayindex = Math.max(maxDisplayindex,oper.view.displayindex); 1263 | }else{ 1264 | oper.view.displayindex = ++maxDisplayindex; 1265 | } 1266 | //设置宽度和高度. 1267 | oper.view.width = icons['oper'].width; 1268 | oper.view.height = icons['oper'].height; 1269 | flowModle.operations.push(oper); 1270 | } 1271 | for(var i in modelJson.subsequents){ 1272 | var subseq = new Subsequent(modelJson.subsequents[i]); 1273 | if(subseq.view.displayindex){ 1274 | maxDisplayindex = Math.max(maxDisplayindex,oper.view.displayindex); 1275 | }else{ 1276 | subseq.view.displayindex = ++maxDisplayindex; 1277 | } 1278 | //设置宽度和高度. 1279 | subseq.view.width = icons['subseq'].width; 1280 | subseq.view.height = icons['subseq'].height; 1281 | flowModle.subsequents.push(subseq); 1282 | } 1283 | //加载成功后默认选中流程基本信息 1284 | selected=[flowModle.flowInfo]; 1285 | setTimeout(function(){onSelect(flowModle.flowInfo);},0)//触发回调函数 1286 | //加载完后渲染一下。放到另外一个线程去渲染,以保证图像已加载完成。由于浏览器加载图片是异步的,可能需要花较长时间,所以给他200毫秒去加载 1287 | setTimeout(function(){console.log('开始绘图');drawAll(cxt);},200); 1288 | }, 1289 | /**向模型中增加一个Act*/ 1290 | addAct:function(actJson){ 1291 | var act = new Act(actJson); 1292 | act.view.displayindex=++maxDisplayindex; 1293 | //设置宽度和高度. 1294 | act.view.width = icons['act'].width; 1295 | act.view.height = icons['act'].height; 1296 | flowModle.activities.push(act); 1297 | //新添加的对象设置为选中 1298 | selected = [act]; 1299 | onSelect(act); 1300 | drawAll(cxt); 1301 | }, 1302 | /**向模型中增加一个Oper*/ 1303 | addOper:function(operJson){ 1304 | var oper = new Oper(operJson); 1305 | oper.view.displayindex=++maxDisplayindex; 1306 | //设置宽度和高度. 1307 | oper.view.width = icons['oper'].width; 1308 | oper.view.height = icons['oper'].height; 1309 | flowModle.operations.push(oper); 1310 | //新添加的对象设置为选中 1311 | selected = [oper]; 1312 | onSelect(oper); 1313 | drawAll(cxt); 1314 | }, 1315 | addSubseq:function(subseqJson){ 1316 | var subseq = new Subsequent(subseqJson); 1317 | //设置宽度和高度. 1318 | subseq.view.width = icons['subseq'].width; 1319 | subseq.view.height = icons['subseq'].height; 1320 | flowModle.subsequents.push(subseq); 1321 | //新添加的对象设置为选中 1322 | selected = [subseq]; 1323 | onSelect(subseq); 1324 | drawAll(cxt); 1325 | }, 1326 | /**获取画布中心点的坐标*/ 1327 | getCenter:function(){ 1328 | var cwidth = $(c).attr('width').replace('px',''); 1329 | var cheight = $(c).attr('height').replace('px',''); 1330 | var x = Math.floor((cwidth)/2); 1331 | var y = Math.floor((cheight)/2); 1332 | //按坐标系调整 1333 | x = x + originPoint.x; 1334 | y = y + originPoint.y; 1335 | return {x:x,y:y}; 1336 | }, 1337 | /**标红需要暴露出去*/ 1338 | getRedMarked:function(){ 1339 | return redMarked; 1340 | }, 1341 | setRedMarked:function(rm){ 1342 | redMarked=rm; 1343 | }, 1344 | /**把流程模型暴露出去*/ 1345 | getFlowModle:function(){ 1346 | //TODO : 应当深拷贝后再报露出去. 1347 | return flowModle; 1348 | }, 1349 | /**移动坐标系*/ 1350 | moveOriginPoint:function(dx,dy){ 1351 | originPoint.x-=dx; 1352 | originPoint.y-=dy; 1353 | }, 1354 | /**设置鼠标移动控制器*/ 1355 | setDragCtrl:function(ctrl){ 1356 | if(ctrl) 1357 | dragCtrl = ctrl; 1358 | }, 1359 | /**将鼠标控制器复原成默认*/ 1360 | resetDragCtrl:function(){ 1361 | dragCtrl = defualtDragCtrl; 1362 | }, 1363 | /**使整个流程图居中显示*/ 1364 | makeCenter:function(){ 1365 | _makeCenter(); 1366 | }, 1367 | /**给业务对象的属性设值*/ 1368 | setVal:function(prop,value){ 1369 | //先找到选中的业务对象 1370 | if(selected.length==0){ 1371 | return; 1372 | } 1373 | var obj = selected[selected.length-1]; 1374 | var model = obj.model; 1375 | var beforeValue = model[prop]; 1376 | model[prop]=value; 1377 | _onValueChange(obj,prop,beforeValue,value); 1378 | //属性变了有可能影响图形外观 1379 | drawAll(cxt); 1380 | }, 1381 | /**删除一个选中的业务对象(同时级联删除他关联到的子对象)*/ 1382 | deleteSelected:function(){ 1383 | for(var i in selected){ 1384 | _deleteObj(selected[i]); 1385 | } 1386 | //删除后清空selected 1387 | _clearSelected(); 1388 | //重绘一下 1389 | drawAll(cxt); 1390 | }, 1391 | /**判断某字段是否重复*/ 1392 | isRepeate:function(prop,value){ 1393 | if(selected.length==0){ 1394 | return false; 1395 | } 1396 | var obj = selected[selected.length-1]; 1397 | return _isRepeate(obj,prop,value); 1398 | }, 1399 | /**重新设置选中框里的内容*/ 1400 | resetSelected:function(obj){ 1401 | //把选中框清空,然后把Obj放进去 1402 | selected = []; 1403 | if(obj && obj instanceof BussinessObj){ 1404 | selected.push(obj); 1405 | } 1406 | //重绘一下 1407 | drawAll(cxt); 1408 | onSelect(obj);//触发一下相关事件 1409 | }, 1410 | /**断开连接与活动的连接*/ 1411 | disconWithAct:function(){ 1412 | //先找到选中的业务对象 1413 | if(selected.length==0){ 1414 | return; 1415 | } 1416 | var obj = selected[selected.length-1]; 1417 | obj.model.activityId = ''; 1418 | resetControlPoint(obj); 1419 | //重绘一下 1420 | drawAll(cxt); 1421 | }, 1422 | /**断开连接与结果的连接*/ 1423 | disconWithOper:function(){ 1424 | //先找到选中的业务对象 1425 | if(selected.length==0){ 1426 | return; 1427 | } 1428 | var obj = selected[selected.length-1]; 1429 | obj.model.operationId = ''; 1430 | resetControlPoint(obj); 1431 | //重绘一下 1432 | drawAll(cxt); 1433 | }, 1434 | /**重新绘制*/ 1435 | redraw:function(){ 1436 | drawAll(cxt); 1437 | }, 1438 | getImgData:function(){ 1439 | return _getImgData(); 1440 | } 1441 | }; 1442 | //设定鼠标拖动控制器 1443 | defualtDragCtrl = getDefaultDragCtrl(exportObj); 1444 | dragCtrl = defualtDragCtrl; 1445 | return exportObj; 1446 | } 1447 | 1448 | 1449 | /** 1450 | * 显示错误信息给用户 1451 | * 如果不满意显示效果可以另写一个函数把它覆盖掉。 1452 | * @returns 1453 | */ 1454 | function showErrMsg(msg){ 1455 | alert(msg); 1456 | } 1457 | --------------------------------------------------------------------------------