为何使用gooflow:1、兼容性好

2、扩展点很多可以个性化设计

3、配有api文档

4、json格式的数据传输

由于最近项目需要,急需设计一个流程,考虑到时间问题,和用户个性化的需求,没办法跟现在项目的后台集成,所以考虑到选择一款jquery插件,并通过存储过程来集成现在的业务模块。

直接上图了:

双击节点可以选择人员

双击连接线可以选择条件

使用gooflow版本为0.4的 网上可以搜到 另外当前版本有些bug需要自己改。需要提供帮助的可以加我QQ:512948935

gooflow版本为0.6

后台使用的是mvc+spring+NHibernate,主要是保存比较麻烦。

前台js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
<script type="text/javascript">
    var property = {
        toolBtns: ["start""end""task"],
        haveHead: true,
        headBtns: ["save""undo""redo""reload"], //如果haveHead=true,则定义HEAD区的按钮
        haveTool: true,
        haveGroup: true,
        useOperStack: true
    };
    var remark = {
        cursor: "选择指针",
        direct: "转换连线",
        start: "开始结点",
        end: "结束结点",
        task: "任务结点",
        group: "组织划分框编辑开关"
    };
    var gooFlow, focusId, flow_title, flowID;
    $(function () {
        gooFlow = $.createGooFlow($("#flow"), property);
        flow_title = getUrlParam1("title");
        flowID = getUrlParam("flowID");
        if (flow_title != "") {
            //自适应调整
            gooFlow.reinitSize($(this).width() - 5, $(parent).height() - 25);
            gooFlow.setTitle(flow_title + "·流程绘制");
            parent.$('#div_layout').layout('panel''center').panel({
                onResize: function (width, height) {
                    gooFlow.reinitSize(width - 5, height - 30);
                }
            });
        }
        else
            gooFlow.reinitSize($(this).width() - 5, $(this).height() - 5);
        if (flowID == "") flowID = 0;
        gooFlow.setNodeRemarks(remark);
        //新建流程
        gooFlow.onBtnNewClick = function () {
            gooFlow.clearData();
        }
        //保存流程
        gooFlow.onBtnSaveClick = function () {
            var h = gooFlow.$bgDiv.height();
            $("<div class=\"datagrid-mask\"></div>").css({ display: "block", width: "100%", height: h }).appendTo(gooFlow.$bgDiv);
            $("<div class=\"datagrid-mask-msg\"></div>").html("数据正在保存中,请稍候……").appendTo(gooFlow.$bgDiv).css({
                display: "block",
                left: (gooFlow.$bgDiv.width() - 200) / 2,
                top: (h - 45) / 2
            });
            var obj = gooFlow.exportAlter();
            //节点
            var nodeData = "";
            for (var in obj.nodes) {
                var id = gooFlow.$nodeData[i].ID == null ? 0 : gooFlow.$nodeData[i].ID;
                var userID = gooFlow.$nodeData[i].userID == null ? 0 : gooFlow.$nodeData[i].userID;
                nodeData += '{"ID": ' + id + ''
                                     ',"FlowID": ' + flowID + ''
                                     ',"NodeID": "' + i + '"'
                                     ',"UserID": "' + userID + '"'
                                     ',"UserName": "' + gooFlow.$nodeData[i].name + '"'
                                     ',"NodeType":  "' + gooFlow.$nodeData[i].type + '"'
                                     ',"NodeLeft":  ' + gooFlow.$nodeData[i].left + ''
                                     ',"NodeTop":  ' + gooFlow.$nodeData[i].top + ''
                                     ',"NodeWidth":  ' + gooFlow.$nodeData[i].width + ''
                                     ',"NodeHeight":  ' + gooFlow.$nodeData[i].height + ''
                                     ',"Marked": false},';
            }
            if (nodeData != "") {
                nodeData = "[" + $.trimend(nodeData, ',') + "]";
            }
            //连接线
            var lineData = "";
            for (var in obj.lines) {
                var id = gooFlow.$lineData[i].ID == null ? 0 : gooFlow.$lineData[i].ID;
                var conditionID = gooFlow.$lineData[i].conditionID == null ? 0 : gooFlow.$lineData[i].conditionID;
                var lineM = gooFlow.$lineData[i].M == null ? 0 : gooFlow.$lineData[i].M;
                lineData += '{"ID": ' + id + ''
                                  ',"FlowID": ' + flowID + ''
                                     ',"LineID": "' + i + '"'
                                     ',"ConditionID": ' + conditionID + ''
                                     ',"ConditionName": "' + gooFlow.$lineData[i].name + '"'
                                     ',"LineType":  "' + gooFlow.$lineData[i].type + '"'
                                     ',"LineFrom":  "' + gooFlow.$lineData[i].from + '"'
                                     ',"LineTo":  "' + gooFlow.$lineData[i].to + '"'
                                     ',"LineM":  ' + lineM + ''
                                     ',"Marked": false},';
            }
            if (lineData != "") {
                lineData = "[" + $.trimend(lineData, ',') + "]";
            }
            //区域
            var areaData = "";
            for (var in obj.areas) {
                var id = gooFlow.$areaData[i].ID == null ? 0 : gooFlow.$areaData[i].ID;
                areaData += '{"ID": ' + id + ''
                                     ',"FlowID": ' + flowID + ''
                                     ',"AreaID": "' + i + '"'
                                     ',"AreaName":  "' + gooFlow.$areaData[i].name + '"'
                                     ',"AreaLeft":  ' + gooFlow.$areaData[i].left + ''
                                     ',"AreaTop":  ' + gooFlow.$areaData[i].top + ''
                                     ',"AreaWidth":  ' + gooFlow.$areaData[i].width + ''
                                     ',"AreaHeight":  ' + gooFlow.$areaData[i].height + ''
                                     ',"AreaColor":  "' + gooFlow.$areaData[i].color + '"'
                                     ',"Marked": false},';
            }
            if (areaData != "") {
                areaData = "[" + $.trimend(areaData, ',') + "]";
            }
            if (nodeData == "" && lineData == "" && areaData == "") {
                $('.datagrid-mask-msg').remove();
                $('.datagrid-mask').remove();
                return;
            }
            $.ajax({
                type: "post",
                url: "/HR/BacthSave",
                data: { node: nodeData, line: lineData, area: areaData },
                success: function (data) {
                    if (data.status == 1) {
                        jqAlert('保存成功.''info'"reload");
                    }
                    else
                        jqAlert('保存失败:' + data, 'error')
                    $('.datagrid-mask-msg').remove();
                    $('.datagrid-mask').remove();
                }
            });
        }
        //刷新
        gooFlow.onFreshClick = function () {
            location.reload();
        }
        //单元节点双击事件
        gooFlow.$workArea.delegate(".ico + td""dblclick", { inthis: gooFlow }, function (e) {
            var newId = $(this).parents(".GooFlow_item").attr("id");
            var $frame = $("#frame_choose_aud");
            if ($frame.attr("src") == undefined) {
                focusId = newId;
                $frame.attr("src""/HR/BaseFlowChooseEmp");
            }
            else {
                if (focusId != newId) {
                    focusId = newId;
                    window.frames["choose_aud"].initData();
                }
            }
            $("#div_win_choose_aud").window('open');
        });
        //单元连接线双击事件
        var tmpClk = "PolyLine";
        if (GooFlow.prototype.useSVG != "")
            tmpClk = "g";
        $(gooFlow.$draw).delegate(tmpClk, "dblclick", { inthis: gooFlow }, function (e) {
            if (GooFlow.prototype.useSVG != "") {
                var $frame = $("#frame_choose_con");
                if ($frame.attr("src") == undefined) {
                    focusId = this.id;
                    $frame.attr("src""/HR/BaseFlowCondition?typeID=" + getUrlParam("typeID"));
                }
                else {
                    if (focusId != this.id) {
                        focusId = this.id;
                        window.frames["choose_con"].unselect();
                    }
                }
                $("#div_win_choose_con").window('open');
            }
        });
        //操作单元删除事件
        gooFlow.onItemDel = function (id, type) {
            var delItem = gooFlow.getItemInfo(id, type);
            if (delItem.ID != null) {
                uiConfirm("确定要删除该单元吗."function () {
                    $.post("/HR/DeleteFlowItem", { "id": id, "type": type }, function (data) {
                        if (data.status == 1) {
                            delItem.ID = null;
                            if (type == "node")
                                gooFlow.delNode(id);
                            else if (type == "line")
                                gooFlow.delLine(id);
                            else if (type == "area")
                                gooFlow.delArea(id);
                            return true;
                        }
                        else
                            jqAlert('删除失败:' + data, 'error')
                    });
                });
            }
            else
                return true
        }
        //初始化人员选择窗体
        showMyWindow($("#div_win_choose_aud"), '选择人员信息''icon-edit''', 900, 450, true);
        //初始化人员选择窗体
        showMyWindow($("#div_win_choose_con"), '选择条件信息''icon-edit''', 900, 450, true);
        //加载数据
        var h = gooFlow.$bgDiv.height();
        $("<div class=\"datagrid-mask\"></div>").css({ display: "block", width: "100%", height: h }).appendTo(gooFlow.$bgDiv);
        $("<div class=\"datagrid-mask-msg\"></div>").html("图形正在加载中,请稍候……").appendTo(gooFlow.$bgDiv).css({
            display: "block",
            left: (gooFlow.$bgDiv.width() - 200) / 2,
            top: (h - 45) / 2
        });
        var para = { "type""get""url""/HR/LoadWorkArea?flowID=" + flowID, "success": onLoadSuccess, "error": onLoadError };
        gooFlow.loadDataAjax(para);
    });
    function onLoadSuccess(msg) {
        $('.datagrid-mask-msg').remove();
        $('.datagrid-mask').remove();
    }
    function onLoadError(status, errorThrown) {
        $('.datagrid-mask-msg').remove();
        $('.datagrid-mask').remove();
    }
    function backAudChoose(row) {
        gooFlow.setName(focusId, row.user_truename + "(" + row.user_no + ")""node");
        var focusNode = gooFlow.getItemInfo(focusId, "node");
        focusNode.name = row.user_truename + "(" + row.user_no + ")";
        focusNode.userID = row.ID;
        $("#div_win_choose_aud").window('close');
    }
    function backConChoose(row) {
        gooFlow.setName(focusId, row.ConditionName, "line")
        var focusLine = gooFlow.getItemInfo(focusId, "line");
        focusLine.name = row.ConditionName;
        focusLine.conditionID = row.ID;
        $("#div_win_choose_con").window('close');
    }
</script>

  后台处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#region BaseFlowPicture
       public ActionResult BaseFlowPicture()
       {
           return View();
       }
       public ActionResult BacthSave(string node = ""string line = ""string area = "")
       {
           try
           {
               if (node != "")
               {
                   List<Q_HR_WorkFlow_Node> nodes = JSONStringToList<Q_HR_WorkFlow_Node>(node);
                   int s = nodes.Where(c => c.NodeType == "start").Count();
                   int e = nodes.Where(c => c.NodeType == "end").Count();
                   if (s != 1)
                       throw new Exception("请设置一个开始节点.");
                   if (e != 1)
                       throw new Exception("请设置一个结束节点.");
                   Q_HR_WorkFlow_NodeManage.BatchSave(nodes);
               }
               if (line != "")
               {
                   List<Q_HR_WorkFlow_Line> lines = JSONStringToList<Q_HR_WorkFlow_Line>(line);
                   Q_HR_WorkFlow_LineManage.BatchSave(lines);
               }
               if (area != "")
               {
                   List<Q_HR_WorkFlow_Area> areas = JSONStringToList<Q_HR_WorkFlow_Area>(area);
                   Q_HR_WorkFlow_AreaManage.BatchSave(areas);
               }
               return Json(new { status = 1 }, JsonRequestBehavior.AllowGet);
           }
           catch (Exception ex)
           {
               return Content(ex.Message);
           }
       }
       public string LoadWorkArea(int flowID = 0)
       {
           DataTable nodes = Q_HR_WorkFlow_NodeManage.GetList(flowID);
           DataTable lines = Q_HR_WorkFlow_LineManage.GetList(flowID);
           IList<Q_HR_WorkFlow_Area> areas = Q_HR_WorkFlow_AreaManage.GetList(flowID);
           string jsonStr = "{";
           string alt;
           //jsonStr += "\"initNum\":" + Q_HR_WorkFlow_NodeManage.GetInitNum() + ",";
           if (nodes.Rows.Count > 0)
           {
               jsonStr += "\"nodes\":{";
               foreach (DataRow row in nodes.Rows)
               {
                   alt = "false";
                   if (row["NodeType"].ToString() == "start" || row["NodeType"].ToString() == "end")
                       alt = "true";
                   jsonStr += "\"" + row["NodeID"] + "\":{"
                           "\"ID\":" + row["ID"] + ""
                           ",\"name\":\"" + row["UserName"] + "(" + row["user_no"] + ")\""
                           ",\"userID\":" + row["UserID"] + ""
                           ",\"type\":\"" + row["NodeType"] + "\""
                           ",\"left\":" + row["NodeLeft"] + ""
                           ",\"top\":" + row["NodeTop"] + ""
                           ",\"width\":" + row["NodeWidth"] + ""
                           ",\"height\":" + row["NodeHeight"] + ""
                           ",\"alt\":" + alt + ""
                           ",\"mark\":" + row["Marked"].ToString().ToLower() + ""
                           "},";
               }
               jsonStr = jsonStr.TrimEnd(',') + "},";
           }
           if (lines.Rows.Count > 0)
           {
               jsonStr += "\"lines\":{";
               foreach (DataRow row in lines.Rows)
               {
                   jsonStr += "\"" + row["LineID"] + "\":{"
                           "\"ID\":" + row["ID"] + ""
                           ",\"name\":\"" + row["ConditionName"] + "\""
                           ",\"conditionID\":" + row["ConditionID"] + ""
                           ",\"type\":\"" + row["LineType"] + "\""
                           ",\"from\":\"" + row["LineFrom"] + "\""
                           ",\"to\":\"" + row["LineTo"] + "\""
                           ",\"M\":" + row["LineM"] + ""
                           ",\"mark\":" + row["Marked"].ToString().ToLower() + ""
                           "},";
               }
               jsonStr = jsonStr.TrimEnd(',') + "},";
           }
           if (areas.Count > 0)
           {
               jsonStr += "\"areas\":{";
               foreach (Q_HR_WorkFlow_Area area in areas)
               {
                   jsonStr += "\"" + area.AreaID + "\":{"
                           "\"ID\":" + area.ID + ""
                           ",\"name\":\"" + area.AreaName + "\""
                           ",\"left\":" + area.AreaLeft + ""
                           ",\"top\":" + area.AreaTop + ""
                           ",\"width\":" + area.AreaWidth + ""
                           ",\"height\":" + area.AreaHeight + ""
                           ",\"color\":\"" + area.AreaColor + "\""
                           "},";
               }
               jsonStr = jsonStr.TrimEnd(',') + "},";
           }
           jsonStr = jsonStr.TrimEnd(',') + "}";
           return jsonStr;
       }
       public ActionResult DeleteFlowItem(string id, string type)
       {
           try
           {
               if (type.Equals("node"))
                   Q_HR_WorkFlow_NodeManage.DeleteFlowNode(id, type);
               else if (type.Equals("line"))
                   Q_HR_WorkFlow_LineManage.DeleteFlowLine(id, type);
               else if (type.Equals("area"))
                   Q_HR_WorkFlow_AreaManage.DeleteFlowArea(id, type);
               return Json(new { status = 1 }, JsonRequestBehavior.AllowGet);
           }
           catch (Exception ex)
           {
               return Content(ex.Message);
           }
       }
       #endregion

  

属性名称

作用

$id

装载整个UI的DOM对象的ID。

$bgDiv

最父框架的DIV。

$tool

左侧工具栏JQ对象。

$head

顶部栏标题标签及工具栏按钮。

$title

载入的流程图的名称。

$nodeRemark

左侧工具栏中每一种结点或按钮的说明文字,JSON格式,key为按钮类型名,value为用户自定义文字说明。

$nowType

当前要绘制的对象类型,开始时为“cursor”,即不绘制任何元素,只是作为鼠标指针进行元素选定。

$lineData={}

转换线数据Map集,以id为key,value为详细数据JSON对象。

$lineCount=0

转换线数据的数量。

$nodeData={}

节点数据Map集,以id为key,value为详细数据JSON对象。

$nodeCount=0

节点数据的数量。

$areaData={}

分组区数据Map集,以id为key,value为详细数据JSON对象。

$areaCount=0

分组区数据的数量。

$lineDom={}

转换线DOM展示对象Map集,以id为key,value为详细在DOM对象。

$nodeDom={}

节点JQ展示对象Map集,以id为key,value为详细在JO对象。

$areaDom={}

分组区JQ展示对象Map集,以id为key,value为详细在JO对象。

$max

计算默认ID值的起始SEQUENCE,默认不填时为1。

$focus

当前被选定的结点/转换线ID,如果没选中或者工作区被清空,则为""。

$cursor

鼠标指针在工作区内的样式,初始时为default。

$editable

当前工作区是否可编辑,即是编辑模式还是仅浏览模式。

$workArea

装载结点/线条/分组区域的工作区。

$draw

画矢量线条的容器,处于工作区中。

$group

仅用来装配分组区域DOM元素的容器,处于工作区中。

$ghost

专门用在移动、重置大小等操作时,给用户操作的半透明浮动区。

$textArea

双击操作对象后出现的浮动文本域,用来写重命名方法setName所需的新名称传参。

$lineMove

操作移动折线的中段时用到的浮动DIV

$lineOper

选定一条转换线后出现的浮动操作栏,有改变线的样式和删除线等按钮。

//以下是当初始化的参数property.useOperStack=true且$editable=true时,才存在的属性:

$undoStack=[]

“撤销操作”栈。

$redoStack=[]

重做操作栈。

$isUndo

事务操作标志位,内部调用

$deletedItem={}

在流程图的编辑操作中被删除掉的元素ID集合,元素ID为KEY,元素类型(node,line.area)为VALUE

[GooFlow对象供使用者调用的方法集]

方法名称

作用

setNodeRemarks(remark)

设定左侧工具栏中每一种结点或按钮的说明文字,传参是JSON格式,key为按钮类型名,value为用户自定义文字说明。

switchToolBtn(type)

切换左边工具栏按钮,传参type表示切换成哪种类型的按钮

addNode(id,json)

增加一个结点,传参json内容结构与$nodeData的每个属性单元一样。

getItemInfo(id,type)

根据id这个KEY,和要获取的数据类型type(有”node”,”line”,”area”三种取值),返回相应的结点json数据单元

blurItem()

取消所有结点/连线被选定的状态

focusItem(id,bool)

选定某个结点/转换线;传参bool:TRUE决定了要触发选中事件,FALSE则不触发选中事件,多用在程序内部调用。

moveNode(id,left,top)

移动一个结点到一个新的位置

setName(id,name,type)

设置结点/连线/分组区域的文字信息;传参id为序列,name为新的名称,type为更名对象的数据类型(有”node”,”line”,”area”三种取值)

resizeNode(id,width,height)

重新设置结点的尺寸,开始/结束类型的结点不支持该方法

delNode(id)

删除结点

setTitle(text)

设置流程图的名称

loadData(data)

载入一组数据JSON格式的流程图数据,传参data中有title,nodes,lines,areas四个KEY的数据,还有一个可选属性数据initNum:ID起始序列号最大数字+1——由于绘制的新单元的ID都是按一定序列号及规则自动生成的,为了防止新载入的数据的ID与编辑时新加入的ID值有重复,将给设计器对象对于新生成单元的ID序列一个新的起始序列号;如果传参JSON中没有这个属性,也可以在调用loadData方法前修改设计器对象的$max属性值(其实loadData方法执行时会检查传参中如果有initNum时,将自动给设计器对象的$max赋上此值);

nodes,lines,areas都为一组{key:value}式的Map数据,内容结构分别与GooFlow对象属性中的$nodeData,$lineData,$areaData一致.

loadDataAjax(para)

用AJAX方式,远程读取一组数据;

参数para为JSON结构,与JQUERY中$.ajax()方法的传参一样

需要后台异步返回JSON格式的msg结果,其内容格式与loadData方法的传参一样。

exportData()

把画好的结束导出到一个本函数返回的变量中(其实也可以直接访问GooFlow对象的$nodeData,$lineData,$areaData这三个JSON属性)

exportAlter()

//只把本次编辑流程图中作了变更(包括增删改)的元素导出到一个变量中,以方便用户每次编辑载入的流程图后只获取变更过的数据

transNewId(oldId,newId,type)

变更元素的ID,一般用于快速保存后,将后台返回新元素的ID更新到页面中;type为元素类型(节点,连线,区块)

clearData()

清空工作区及已载入的数据

destrory()

销毁自己

addLine(id,json)

增加一条线,传参json内容结构与$lineData的每个属性单元一样。

setLineType(id,newType)

重新设置连线的样式. 传参newType的取值有:"sl"直线, "lr"中段可左右移动型折线, "tb"中段可上下移动型折线

setLineM(id,M)

设置折线中段的X坐标值(可左右移动时)或Y坐标值(可上下移动时);直线不支持此方法

delLine(id)

删除转换线

markItem(id,type,mark)

//用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。

//这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。

//传参:id是操作单元对象唯一序列号;type是操作单元类型(“node”或者”line”,分组区域不支持此方法);mark为布尔值,表示是否标注/取消标注某个ID值的数据单元对象

addArea(id,json)

增加一个分组区域,传参json内容结构与$areaData的每个属性单元一样。

moveArea(id,left,top)

移动分组区域到新的位置上.

delArea(id)

删除分组区域

setAreaColor(id,color)

设置分组区域的颜色,传参color为颜色样式,只有”red”,”yellow”,”blue”,”green”四种取值

resizeArea(id,width,height)

重新设置区分组区域的尺寸

reinitSize(width,height)

重构整个流程图设计器的宽高,在浏览器窗口大小改变或者父容器宽高改变时,执行这个方法能让设计器重新适应新的宽高显示。

//以下是当初始化的参数property.useOperStack=true时,才存在的方法:

pushOper(funcName,paras)

仅供内部方法调用的方法:把对工作区内的数据单元编辑操作(增/删/改/重命名/移动/标注等)加入整条管理栈中,好进入撤销/重做的控制;

注意:将为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存。

pushExternalOper

(func,jsonPara)

//将外部的方法加入到GooFlow对象的事务操作堆栈中,在过后的undo/redo操作中可以进行控制,一般用于对流程图以外的附加信息进行编辑的事务撤销/重做控制;

//传参func为要执行方法对象,jsonPara为外部方法仅有的一个面向字面的JSON传参或者数据,由JSON对象或数组带入所有要传的信息;

//提示:为了让外部方法能够被UNDO/REDO,需要在编写这些外部方法实现时,加入对该方法执行后效果回退的另一个执行方法的pushExternalOper。

undo()

撤销最近一次操作

redo()

重做最近一次被撤销的操作

gooflow的流程设计相关推荐

  1. 驰骋工作流程引擎案例-水质检测工作流程设计开发实现过程

    2019独角兽企业重金招聘Python工程师标准>>> Technorati Tags: 开源驰骋工作流引擎, .NET工作流,表单设计器,ccflow, jflow, 案例,水质监 ...

  2. 移动端与PHP服务端接口通信流程设计(基础版)

    为什么80%的码农都做不了架构师?>>>    针对 --->非开放性平台 --->公司内部产品 接口特点汇总: 1.因为是非开放性的,所以所有的接口都是封闭的,只对公司 ...

  3. 制造业采购审批流程设计示例

    随着中国企业管理水平的不断提高,OA办公软件的使用越来越广泛了.办公软件实际上是一种管理思想的体现,只有具备了正确的管理思想才能有正确的软件.下面举一个具体的例子来谈谈如何开发OA办公系统的审批流程. ...

  4. 驰骋工作流引擎设计系列05 启动流程设计

    2019独角兽企业重金招聘Python工程师标准>>> 启动流程设计 第1节. 关键字 驰骋工作流引擎 流程快速开发平台 workflow ccflow jflow 第1节. 启动流 ...

  5. 文件上传下载流程设计

    最近在写一个文件上传下载的服务端和客户端,在开发之前把交互流程大概设计了一下顺便分享出来,流程主要包括验证,交口端口验证,文件上和文件下载等功能.之于文件删除,在线压缩和解压等流程相对简单所以就不列出 ...

  6. 云ERP系统如何进行流程设计

    2019独角兽企业重金招聘Python工程师标准>>> ERP的应用一直都有很多的困扰在困着这CIO,然而对于ERP的流程设计又是让人头痛的问题.需要考虑多方因素才能确保企业云ERP ...

  7. asp.net 微信企业号办公系统-流程设计--保存与发布

    如果流程未设计完时可以先保存,以后再打开接着设计.点击工具栏上的保存按钮即可保存当前流程设计: 如果下次要接着设计,则可以打开该流程继续设计: 如果流程设计完成,可以点击安装按钮来发布流程,流程安装成 ...

  8. spring催办业务_业务后台系统之流程设计

    上周在<业务后台系统之权限设计>中总结了自己在最近一个后台业务系统项目中的后台产品设计经验,本篇继续总结完后台设计三大内容中的流程设计. 首先,需要明确工作流联盟(WFMC)对工作流的定义 ...

  9. 流程设计建模方法:流程的需求梳理之流程级别梳理

    一般而言,对于一个业务系统的开发过程,可以划分成:需求.设计.开发.测试.集成.部署等阶段.在需求阶段形成<需求规格说明书>之后,设计阶段需要对需求进行设计建模.业务流程需求是业务人员从业 ...

  10. 流程设计建模方法:流程的需求梳理之活动级别梳理

    业务需求建模是否合理,直接影响到流程的技术实现,在流程设计过程中首先需要对业务需求从技术实现的角度重新进行梳理.下图是业务流程需求梳理过程的示意图: 本文介绍活动级别梳理方法 活动级别需求梳理是对流程 ...

最新文章

  1. D3.js可视化库入门视频教程
  2. 互联网公装企业“inDeco领筑智造”完成A+B轮近1.1亿元融资
  3. EasyUI-DataGrid之批量删除
  4. java操作ad域 免证书
  5. 用什么方式链接oracle数据库,使用cx_Oracle 连接oracle数据库的几种方式
  6. 每日干货丨C语言数组知识点总结
  7. 前端学习(1189):事件基本使用
  8. c语言作业重庆科技学院,C语言程序设计学生上机报告-NO3.doc
  9. 中国信通院发布《数据库发展研究报告(2021年)》(附报告和解读PPT下载)
  10. c# -- 动态生成查询lamda表达式
  11. 转 使用vim时按了CTRL+S键怎么办?
  12. Codepen 每日精选(2018-3-29)
  13. MyEclipse + Tomcat 热部署问题
  14. Linux模块化增加设备驱动程序
  15. python如何速成_怎样速成python?
  16. VS 下环境覆盖率测试
  17. 关于百度有啊的几点看法
  18. 170402网摘题目
  19. 商鞅(约公元前395年-公元前338年)
  20. 利用matlab画地图

热门文章

  1. 如何连接到sqlplus
  2. 点播系统加服务器加投影加音响,VOD视频点播系统的安装维护与使用
  3. 服装进销存管理软件榜单前十排名
  4. python csv生成vcf
  5. android手机通讯录格式转换,手机通讯录csv格式转vcf格式工具 安卓电话本数据格式转换程序...
  6. 开源面向对象数据库 db4o 之旅,第 1 部分: 初识 db4o
  7. 从球衣了解“红魔”曼联历史
  8. 使用Mediacoder压制带有图片的ass字幕
  9. 高等代数第3版下 [丘维声 著] 2015年版_全国硕士研究生入学统一考试管理类联考综合能力考试大纲(2021年版)...
  10. 一周学会linux实战 下载 pdf_UOS可用的pdf编辑工具