gooflow0.6的流程设计

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

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

                       3、配有api文档

                       4、json格式的数据传输

gooflow0.8版

gooflow2.0版

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

 

直接上图了:

双击节点可以选择人员

双击连接线可以选择条件

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

gooflow版本为0.6

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

 前台js

<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 i 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 i 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 i 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>

  后台处理

 #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()

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

posted @ 2015-01-17 09:37  Taffy++  阅读(18620)  评论(3编辑  收藏  举报