RuleFlowDesigner.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /**
  2. * Created by jacky on 2016/7/18.
  3. */
  4. import {FlowDesigner,MsgBox} from 'flowdesigner';
  5. import BaseNode from './BaseNode.js';
  6. import * as event from '../components/componentEvent.js';
  7. import * as action from '../frame/action.js';
  8. import {Event,Node} from 'flowdesigner';
  9. import * as CONSTANTS from './Constants.js';
  10. export default class RuleFlowDesigner extends FlowDesigner{
  11. constructor(containerId){
  12. super(containerId);
  13. this.importVariableLibraries=[];
  14. this.importConstantLibraries=[];
  15. this.importParameterLibraries=[];
  16. this.importActionLibraries=[];
  17. this.variableLibraries=[];
  18. this.constantLibraries=[];
  19. this.parameterLibraries=[];
  20. this.actionLibraries=[];
  21. this.flowId='';
  22. }
  23. toXML(){
  24. if(!this.flowId || this.flowId.length<1){
  25. MsgBox.alert('决策流ID必须指定!');
  26. return;
  27. }
  28. if(!this.validate()){
  29. return;
  30. }
  31. if(this.toJSON().length<2){
  32. MsgBox.alert('决策流至少要包含一个开始节点和一个其它类型节点!');
  33. return;
  34. }
  35. let debug=false;
  36. if(this.debug!==undefined && this.debug!==null){
  37. debug=this.debug;
  38. }
  39. let xml='<?xml version="1.0" encoding="utf-8"?>';
  40. xml+=`<rule-flow id="${this.flowId}" debug="${debug}">`;
  41. for(let lib of this.importVariableLibraries){
  42. xml+=`<import-variable-library path="${lib}"/>`;
  43. }
  44. for(let lib of this.importConstantLibraries){
  45. xml+=`<import-constant-library path="${lib}"/>`;
  46. }
  47. for(let lib of this.importParameterLibraries){
  48. xml+=`<import-parameter-library path="${lib}"/>`;
  49. }
  50. for(let lib of this.importActionLibraries){
  51. xml+=`<import-action-library path="${lib}"/>`;
  52. }
  53. for(let figure of this.context.allFigures){
  54. if(!(figure instanceof BaseNode)){
  55. continue;
  56. }
  57. xml+=figure.toXML();
  58. }
  59. xml+='</rule-flow>';
  60. xml=encodeURI(xml);
  61. return xml;
  62. }
  63. fromJson(json){
  64. this.flowId=json.id;
  65. this.debug=json.debug;
  66. const libs=json.libraries || [];
  67. for(let lib of libs){
  68. switch (lib.type){
  69. case "Variable":
  70. this.importVariableLibraries.push(lib.path);
  71. break;
  72. case "Constant":
  73. this.importConstantLibraries.push(lib.path);
  74. break;
  75. case "Action":
  76. this.importActionLibraries.push(lib.path);
  77. break;
  78. case "Parameter":
  79. this.importParameterLibraries.push(lib.path);
  80. break;
  81. }
  82. }
  83. if(this.importVariableLibraries.length>0){
  84. this._refreshLibraries(this.importVariableLibraries,"vl.xml");
  85. }
  86. if(this.importConstantLibraries.length>0){
  87. this._refreshLibraries(this.importConstantLibraries,"cl.xml");
  88. }
  89. if(this.importActionLibraries.length>0){
  90. this._refreshLibraries(this.importActionLibraries,"al.xml");
  91. }
  92. if(this.importParameterLibraries.length>0){
  93. this._refreshLibraries(this.importParameterLibraries,"pl.xml");
  94. }
  95. for(let nodeJson of json.nodes){
  96. nodeJson.w=nodeJson.width;
  97. nodeJson.h=nodeJson.height;
  98. switch (nodeJson.type){
  99. case "Action":
  100. nodeJson.type='动作';
  101. break;
  102. case "Script":
  103. nodeJson.type='脚本';
  104. break;
  105. case "Decision":
  106. nodeJson.type='决策';
  107. break;
  108. case "End":
  109. nodeJson.type='结束';
  110. break;
  111. case "Start":
  112. nodeJson.type='开始';
  113. break;
  114. case "Rule":
  115. nodeJson.type='规则';
  116. break;
  117. case "RulePackage":
  118. nodeJson.type='知识包';
  119. break;
  120. case "Fork":
  121. nodeJson.type='分支';
  122. break;
  123. case "Join":
  124. nodeJson.type='聚合';
  125. break;
  126. }
  127. const conns=nodeJson.connections || [];
  128. for(let conn of conns){
  129. conn.to=conn.toName;
  130. }
  131. this.addNode(nodeJson);
  132. }
  133. for(let figure of this.context.allFigures){
  134. if(!(figure instanceof Node)){
  135. continue;
  136. }
  137. figure._buildConnections();
  138. }
  139. }
  140. getPropertiesProducer(){
  141. const _this=this;
  142. return function (){
  143. const g=$('<div></div>');
  144. const flowIdGroup=$(`<div class="form-group"><label>决策流ID</label></div>`);
  145. const flowIdText=$(`<input type="text" class="form-control">`);
  146. flowIdGroup.append(flowIdText);
  147. const _this=this;
  148. flowIdText.change(function(){
  149. _this.flowId=$(this).val();
  150. });
  151. flowIdText.val(this.flowId);
  152. g.append(flowIdGroup);
  153. const debugGroup=$(`<div class="form-group"><label>允许调试信息输出</label></div>`);
  154. const debugSelect=$(`<select class="form-control">
  155. <option value="true" ${_this.debug ? "selected" : ""}>是</option>
  156. <option value="false" ${_this.debug ? "" : "selected"}>否</option>
  157. </select>`);
  158. debugGroup.append(debugSelect);
  159. debugSelect.change(function(){
  160. _this.debug=$(this).val();
  161. });
  162. g.append(debugGroup);
  163. const libGroup=$('<div class="form-group"><label>库文件</label></div>');
  164. const addButton=$(`<span style="float: right;"><button type="button" class="btn btn-info"><i class="glyphicon glyphicon-plus"></i> 添加</button></span>`);
  165. libGroup.append(addButton);
  166. addButton.click(function () {
  167. event.eventEmitter.emit(event.OPEN_KNOWLEDGE_TREE_DIALOG,{
  168. project:window._project,
  169. forLib:true,
  170. callback:function (file,version) {
  171. let fullFileName=file+(version==='LATEST' ? '' : ':'+version);
  172. const extPos=file.indexOf('.')+1;
  173. const extName=file.substring(extPos,file.length);
  174. let importLibs=null;
  175. if(extName==='vl.xml'){
  176. importLibs=_this.importVariableLibraries;
  177. }else if(extName==='cl.xml'){
  178. importLibs=_this.importConstantLibraries;
  179. }else if(extName==='pl.xml'){
  180. importLibs=_this.importParameterLibraries;
  181. }else if(extName==='al.xml'){
  182. importLibs=_this.importActionLibraries;
  183. }else{
  184. alert(`Unknow lib [${file}]`);
  185. return;
  186. }
  187. fullFileName="jcr:"+fullFileName;
  188. const pos=importLibs.indexOf(fullFileName);
  189. if(pos>-1){
  190. MsgBox.alert(`库文件${file}已存在!`);
  191. return;
  192. }
  193. const extCName=action.buildType(extName);
  194. const newRow=$(`<tr>
  195. <td style="font-size: 11px;word-break: break-all">${fullFileName}</td>
  196. <td style="text-align: center">${extCName}</td>
  197. </tr>`);
  198. importLibs.push(fullFileName);
  199. const delCol=$('<td style="text-align: center"></td>');
  200. newRow.append(delCol);
  201. const delButton=$(`<div class="btn btn-link" style="padding: 0">删除</div>`);
  202. delCol.append(delButton);
  203. delButton.click(function () {
  204. const pos=importLibs.indexOf(fullFileName);
  205. importLibs.splice(pos,1);
  206. newRow.remove();
  207. _this._refreshLibraries(importLibs,extName);
  208. });
  209. tbody.append(newRow);
  210. _this._refreshLibraries(importLibs,extName);
  211. }
  212. });
  213. });
  214. const table=$('<table class="table table-bordered" style="table-layout: fixed">');
  215. const thead=$(`<thead>
  216. <tr>
  217. <td>库文件路径</td><td style="width: 60px">类型</td><td style="width: 50px">删除</td>
  218. </tr>
  219. </thead>`);
  220. table.append(thead);
  221. const tbody=$('<tbody>');
  222. table.append(tbody);
  223. function initLibraries(libraries) {
  224. for(let lib of libraries){
  225. let pos=lib.indexOf(":"),extName;
  226. if(pos>-1){
  227. const libName=lib.substring(pos+1,lib.length);
  228. pos=libName.indexOf('.')+1;
  229. extName=libName.substring(pos,libName.length);
  230. }else{
  231. pos=lib.indexOf('.')+1;
  232. extName=lib.substring(pos,lib.length);
  233. }
  234. const extCName=action.buildType(extName);
  235. const newRow=$(`<tr>
  236. <td style="font-size: 11px;word-break: break-all">${lib}</td>
  237. <td style="text-align: center">${extCName}</td>
  238. </tr>`);
  239. const delCol=$('<td style="text-align: center"></td>');
  240. newRow.append(delCol);
  241. const delButton=$(`<div class="btn btn-link" style="padding: 0">删除</div>`);
  242. delCol.append(delButton);
  243. delButton.click(function () {
  244. const pos=libraries.indexOf(lib);
  245. libraries.splice(pos,1);
  246. newRow.remove();
  247. _this._refreshLibraries(libraries,extName);
  248. });
  249. tbody.append(newRow);
  250. }
  251. }
  252. initLibraries(_this.importVariableLibraries);
  253. initLibraries(_this.importParameterLibraries);
  254. initLibraries(_this.importConstantLibraries);
  255. initLibraries(_this.importActionLibraries);
  256. libGroup.append(table);
  257. g.append(libGroup);
  258. return g;
  259. }
  260. }
  261. _refreshLibraries(importLibs,extName) {
  262. if(importLibs.length===0){
  263. return;
  264. }
  265. let libs=null;
  266. const _this=this;
  267. this._loadLibraries(importLibs,function (result) {
  268. if(extName==='vl.xml'){
  269. libs=_this.variableLibraries;
  270. libs.splice(0,libs.length);
  271. for(let category of result){
  272. libs.push(...category);
  273. }
  274. }else if(extName==='cl.xml'){
  275. libs=_this.constantLibraries;
  276. libs.splice(0,libs.length);
  277. for(let category of result){
  278. libs.push(...category.categories);
  279. }
  280. }else if(extName==='pl.xml'){
  281. libs=_this.variableLibraries;
  282. let paramCategory,param1Category;
  283. for(let category of libs){
  284. if(category.name==='参数'){
  285. paramCategory=category;
  286. }
  287. if(category.name==='parameter'){
  288. param1Category=category;
  289. }
  290. }
  291. if(!paramCategory){
  292. paramCategory={
  293. type:'variable',
  294. name:'参数'
  295. };
  296. libs.push(paramCategory);
  297. }
  298. if(!param1Category){
  299. param1Category={
  300. type:'variable',
  301. name:'parameter'
  302. };
  303. libs.push(param1Category);
  304. }
  305. paramCategory.variables=result[0];
  306. param1Category.variables=result[0];
  307. }else if(extName==='al.xml'){
  308. importLibs=_this.importActionLibraries;
  309. libs=_this.actionLibraries;
  310. libs.splice(0,libs.length);
  311. libs.push(...result);
  312. }
  313. Event.eventEmitter.emit(CONSTANTS.LIB_CHANGE,{
  314. actionLibraries:_this.actionLibraries,
  315. constantCategories:_this.constantLibraries,
  316. parameterLibraries:_this.parameterLibraries,
  317. variableCategories:_this.variableLibraries
  318. });
  319. });
  320. };
  321. _loadLibraries(importLibs,callback){
  322. let files="";
  323. for(var i=0;i<importLibs.length;i++){
  324. const libFile=importLibs[i];
  325. if(i==0){
  326. files=libFile;
  327. }else{
  328. files+=";"+libFile;
  329. }
  330. }
  331. if(files.length<2){
  332. return;
  333. }
  334. var url=window._server+"/common/loadXml";
  335. $.ajax({
  336. url,
  337. data:{files},
  338. type:'POST',
  339. error:function(response){
  340. if(response && response.responseText){
  341. bootbox.alert("<span style='color: red'>加载库文件失败,服务端错误:"+response.responseText+"</span>");
  342. }else{
  343. bootbox.alert("<span style='color: red'>加载库文件失败,服务端出错</span>");
  344. }
  345. },
  346. success:function(data){
  347. callback(data);
  348. }
  349. });
  350. };
  351. }