C# 实现改造 GooFlow 流程图插件与数据库应用的结合

 

目录

关于 GooFlow

功能需求

范例运行环境

设计数据表

流程项目表

流程项目节点明细表

流程项目节点审批人表

 人员信息表

示例代码

流程图主功能

设置审批人信息

运行结果演示

总结


关于 GooFlow

GooFlow 一个基于 Jquery/FontAwesome 的流程图/架构图画图插件,本文介绍的是基于JS的一个版本,能够适用于大部分支持H5的浏览器。通过创建画布,我们可以在其上通过工具栏绘制想要绘制的流程图/框/线等,如下图所示:

图中包括操作工具栏(顶部)、绘图工具栏(左侧)和绘制画布区域,左上角显示的是当前流程的名称。 具体的操作我们不再详述,本文将介绍通过改造后的 GooFlow 简化版本,结合数据库满足实际的开发需求。

功能需求

我们需要实现一个审批流程,在关键流程节点可能会添加审批人信息,通过GoolFlow绘制并显示,则更加友好和直观, 基本需要实现如下功能:

1、改造 GooFlow JS 程序,简化绘制工具栏。

2、设计相关数据库数据表保存流程图设计相关信息、节点明细信息等。

3、改造 GooFlow 操作工具栏,满足实际应用。

范例运行环境

操作系统: Windows Server 2019 DataCenter

GooFlow 版本:GooFlow V1 JS 版 

数据库:Microsoft SQL Server 2016

.net版本: .netFramework4.7.1 或以上

开发工具:VS2019  C#

设计数据表

流程项目表

cc_flow 表记录项目信息,主要说明见下表:

序号字段名类型说明
1ciduniqueidentifier记录唯一标识
2flowNamenvarchar(50)流程项目名称
3nodeCountint节点总个数
4desriptnvarchar(50)项目描述
5flowJSONnvarchar(MAX)流程全部 JSON 数据
6sys_insusernvarchar(100)创建信息用户名
7sys_instimedatetime创建时间
8sys_updusernvarchar(100)最后修改信息用户名
9sys_updtimedatetime修改时间

 创建脚本如下:

CREATE TABLE [dbo].[cc_flow]([cid] [uniqueidentifier] ROWGUIDCOL  NOT NULL,[flowName] [nvarchar](50) NOT NULL,[nodeCount] [int] NULL,[desript] [nvarchar](100) NULL,[flowJSON] [nvarchar](max) NULL,[sys_insuser] [nvarchar](100) NULL,[sys_instime] [datetime] NULL,[sys_upduser] [nvarchar](100) NULL,[sys_updtime] [datetime] NULL,CONSTRAINT [PK_cc_flow] PRIMARY KEY CLUSTERED 
([cid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],CONSTRAINT [IX_cc_flow] UNIQUE NONCLUSTERED 
([flowName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GOALTER TABLE [dbo].[cc_flow] ADD  CONSTRAINT [DF_cc_flow_cid]  DEFAULT (newid()) FOR [cid]
GO

流程项目节点明细表

cc_flowNodes 表记录了项目绘制节点的所有信息明细情况,主要说明见下表:

序号字段名类型说明
1ciduniqueidentifier记录唯一标识
2nodeIdnvarchar(50)节点ID
3nodeNamenvarchar(50)节点流程名称
4desriptnvarchar(100)节点流程描述
5parentNodeIdnvarchar(50)父节点ID
6projectCiduniqueidentifier流程项目ID,所属的项目唯一标识
7sortidint节点排序
8sys_insusernvarchar(100)创建信息用户名
9sys_instimedatetime创建时间
10sys_updusernvarchar(100)最后修改信息用户名
11sys_updtimedatetime修改时间

 创建脚本如下:

CREATE TABLE [dbo].[cc_flowNodes]([cid] [uniqueidentifier] NOT NULL,[nodeId] [nvarchar](50) NOT NULL,[nodeName] [nvarchar](50) NOT NULL,[desript] [nvarchar](100) NULL,[parentNodeId] [nvarchar](50) NULL,[projectCid] [uniqueidentifier] NOT NULL,[sortid] [int] NULL,[sys_insuser] [nvarchar](100) NULL,[sys_instime] [datetime] NULL,[sys_upduser] [nvarchar](100) NULL,[sys_updtime] [datetime] NULL
) ON [PRIMARY]
GOALTER TABLE [dbo].[cc_flowNodes] ADD  CONSTRAINT [DF_cc_flowNodes_cid]  DEFAULT (newid()) FOR [cid]
GO
流程项目节点审批人表

cc_flowNodeAccounts 表记录了项目关键节点的参与审批人情况,主要说明见下表:

序号字段名类型说明
1ciduniqueidentifier记录唯一标识
2nodeIdnvarchar(50)节点ID
3AccountCiduniqueidentifier所属的人员信息ID
4desriptnvarchar(100)描述,可以记录诸如姓名相关的一些信息
5rolenvarchar(50)审批人权限(如决策、抄送)
6projectCiduniqueidentifier流程项目ID,所属的项目唯一标识
7sys_insusernvarchar(100)创建信息用户名
8sys_instimedatetime创建时间
9sys_updusernvarchar(100)最后修改信息用户名
10sys_updtimedatetime修改时间

 创建脚本如下:


CREATE TABLE [dbo].[cc_flowNodeAccounts]([cid] [uniqueidentifier] NOT NULL,[projectCid] [uniqueidentifier] NOT NULL,[AccountCid] [uniqueidentifier] NOT NULL,[descript] [nvarchar](100) NULL,[nodeId] [nvarchar](50) NOT NULL,[role] [nvarchar](50) NULL,[sys_insuser] [nvarchar](100) NULL,[sys_instime] [datetime] NULL,[sys_upduser] [nvarchar](100) NULL,[sys_updtime] [datetime] NULL
) ON [PRIMARY]
GOALTER TABLE [dbo].[cc_flowNodeAccounts] ADD  CONSTRAINT [DF_cc_flowNodeBuss_cid]  DEFAULT (newid()) FOR [cid]
GO
 人员信息表

accounts 表审批人的基本个人情况,主要说明见下表:

序号字段名类型说明
1ciduniqueidentifier记录唯一标识
2namenvarchar(50)姓名
3nickNamenvarchar(50)昵称

 创建脚本如下:


CREATE TABLE [dbo].[accounts]([cid] [uniqueidentifier] ROWGUIDCOL  NOT NULL,[name] [nvarchar](50) NULL,[nickname] [nvarchar](500) NULL,CONSTRAINT [PK_wxmp_accounts] PRIMARY KEY CLUSTERED 
([cid] ASC
)
)
GOALTER TABLE [dbo].[accounts] ADD  CONSTRAINT [DF_wxmp_accounts_cid]  DEFAULT (newid()) FOR [cid]
GO

示例代码

流程图主功能

本示例代码包含后端、前端及 JS 代码,代码如下:

<%@ Page Language="C#" AutoEventWireup="true" MaintainScrollPositionOnPostback="true"  ValidateRequest="FALSE" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %><script language="C#" runat="server">public CosysJaneCommonAPI.CODAL dal = new CosysJaneCommonAPI.CODAL();public DateTime dt = DateTime.Now;void Page_load(Object sender, EventArgs e){dal.RunAt = Form;if (Page.IsPostBack == true) return;dal.ConnKeyString = "JaneConnectionCloud";ArrayList paras = new ArrayList();paras.Clear();paras.Add(new SqlParameter("a", "2"));dal.simpledatalist("select cid,flowName from cc_flow order by flowName ", paras, "cid", "flowName",flowlist, true, "", "选择打开已创建流程");}protected void saveflow_Click(object sender, EventArgs e){dal.ConnKeyString = "JaneConnectionCloud";ArrayList paras = new ArrayList();paras.Clear();paras.Add(new SqlParameter("flowname", x_flowname.Text));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("insert into cc_flow (flowName) values(@flowname) ", paras);if (dal.RowsCount > 0){tip.Text = "创建成功!";flowpanel.Visible = true;}else{if (dal.ErrorMessage.IndexOf("重复键") != -1){dal.RowsCount = 0;dal.ErrorMessage = "";paras.Clear();paras.Add(new SqlParameter("flowname", x_flowname.Text));object rv = dal.GetDataSet("select * from  cc_flow where flowname=@flowname ", paras);if (dal.RowsCount > 0){DataSet ds = rv as DataSet;DataTable dt = ds.Tables[0];x_cid.Text = dt.Rows[0]["cid"].ToString();x_flowJSON.Text = dt.Rows[0]["flowJSON"].ToString();tip.Text = "打开成功!";flowpanel.Visible = true;}else{tip.Text = dal.ErrorMessage;flowpanel.Visible = false;}}else{tip.Text = dal.ErrorMessage;flowpanel.Visible = false;}}}protected void updflow_Click(object sender, EventArgs e){dal.ConnKeyString = "JaneConnectionCloud";ArrayList paras = new ArrayList();Newtonsoft.Json.Linq.JObject jsonObj = Newtonsoft.Json.Linq.JObject.Parse(x_flowJSON.Text);string nodelist = "";foreach (Newtonsoft.Json.Linq.JProperty jt in  jsonObj["nodes"]){nodelist+=jt.Name+",";}string cid = x_cid.Text;dal.ConnKeyString = "JaneConnectionCloud";paras.Clear();paras.Add(new SqlParameter("cid", cid));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("delete cc_flowNodes where projectCid=@cid ", paras);string[] la = nodelist.Split(',');int added = 0;for (int i = 0; i < la.GetLength(0); i++){if (la[i] != ""){paras.Clear();paras.Add(new SqlParameter("projectCid", cid));paras.Add(new SqlParameter("parentNodeId", (i == 0 ? cid : la[i - 1])));paras.Add(new SqlParameter("nodeId", la[i]));paras.Add(new SqlParameter("nodeName", jsonObj["nodes"][la[i]]["name"].ToString()));paras.Add(new SqlParameter("sortid", i + 1));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("insert into cc_flowNodes(projectCid,parentNodeId,nodeId,nodeName,sortid) values(@projectCid,@parentNodeId,@nodeId,@nodeName,@sortid) ", paras);if (dal.RowsCount > 0){added++;}}}paras.Clear();paras.Add(new SqlParameter("cid", x_cid.Text));paras.Add(new SqlParameter("flowName",x_flowname.Text));paras.Add(new SqlParameter("flowJSON", x_flowJSON.Text));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("update cc_flow set flowName=@flowname,flowJSON=@flowJSON where cid=@cid ", paras);if (dal.RowsCount > 0){tip.Text = "更新成功!";}else{tip.Text = dal.ErrorMessage;}}protected void flowlist_SelectedIndexChanged(object sender, EventArgs e){if (flowlist.SelectedValue == ""){return;}dal.ConnKeyString = "JaneConnectionCloud";ArrayList paras = new ArrayList();dal.RowsCount = 0;dal.ErrorMessage = "";paras.Clear();paras.Add(new SqlParameter("cid",flowlist.SelectedValue));object rv = dal.GetDataSet("select * from  cc_flow where cid=@cid ", paras);if (dal.RowsCount > 0){DataSet ds = rv as DataSet;DataTable dt = ds.Tables[0];x_cid.Text = dt.Rows[0]["cid"].ToString();x_flowname.Text = dt.Rows[0]["flowName"].ToString();x_flowJSON.Text = dt.Rows[0]["flowJSON"].ToString();tip.Text = "打开成功!";flowpanel.Visible = true;}else{tip.Text = dal.ErrorMessage;flowpanel.Visible = false;}}
</script>        <!DOCTYPE html>
<html lang="cn" >
<head><meta charset="UTF-8"><title></title>
<link rel="stylesheet" href="dist/GooFlow.min.css?v=10" />
<link rel="stylesheet" href="fontawesome/css/font-awesome.min.css" />
</head><script src="dist/jquery.min.js"></script>
<script src="dist/GooFlow.js?v=7"></script>
<body><form runat="server"><div style=" display:flex"><asp:TextBox ID="x_flowname" placeholder="输入项目名称" runat="server"></asp:TextBox><asp:Button ID="saveflow" Text="创建项目" runat="server" onclick="saveflow_Click"></asp:Button><asp:Button ID="updflow" Text="更新项目" style=" display:none" runat="server" onclick="updflow_Click" ></asp:Button><asp:TextBox ID="x_cid" placeholder="cid" style="display:none" ReadOnly="true" runat="server"></asp:TextBox><asp:DropDownList ID="flowlist" runat="server" AutoPostBack="true"onselectedindexchanged="flowlist_SelectedIndexChanged"></asp:DropDownList></div><div style=" margin:10px; display:flex"><asp:Label ID="tip" Text="这是一些提示信息..." runat="server"></asp:Label></div><iframe id="tframe" width="500" height="400" style=" display:none;z-index:99;position:absolute;" runat="server"></iframe><div id="flowpanel" visible="false" runat="server">
</div><div><asp:TextBox ID="x_flowJSON" Rows="10" style="display:none"  width="100%" TextMode="MultiLine" runat="server"></asp:TextBox></div></form>
</body>
</html>
<script language="javascript" type="text/javascript">var tframe=$('#tframe');var curnode=null;var flowpanel=null;var sortBy = function (filed, rev, primer) {rev = (rev) ? -1 : 1;return function (a, b) {a = a[filed];b = b[filed];if (primer && typeof (primer) != 'undefined') {a = primer(a);b = primer(b);}else{if(!isNaN(a) && !isNaN(a)){a = Number(a);b = Number(b);}}if (a < b) { return rev * -1; }if (a > b) { return rev * 1; }return 1;}};$(function(){var options={initLabelText:"未命名",toolBtns:["task","chat","state"],toolBtnRemarks:{cursor:"选择指针",direct:"连线",task:"任务结点",chat:"决策结点",state:"状态结点",group:"组织区域框"},headBtns:["save","undo","redo","new","expand"],headBtnRemarks:['保存','撤销','重做','清空画布','结点设置']};flowpanel = $('#flowpanel').createGooFlow(options);var flowpanelData = {areas: {flowpanel_area_17: {color: "yellow",height: 300,left: 40,name: "部门一",top: 30,width: 150,},flowpanel_area_18: {color: "blue",height: 300,left: 200,name: "部门二",top: 30,width: 150,},flowpanel_area_19: {color: "green",height: 300,left: 360,name: "部门三",top: 30,width: 150,},flowpanel_area_20: {color: "red",height: 300,left: 520,name: "部门四",top: 30,width: 150,},},lines: {flowpanel_line_11: {from: "flowpanel_node_1",marked: false,name: "",to: "flowpanel_node_2",type: "sl",},},nodes: {flowpanel_node_1: {height: 24,left: 70,name: "节点流程1",top: 66,type: "chat",width: 86,sortid:1,id:"flowpanel_node_1",},flowpanel_node_2: {height: 24,left: 240,name: "节点流程2",top: 132,type: "state",width: 86,sortid:2,id:"flowpanel_node_2",},}};flowpanel.loadData(flowpanelData);if($('#x_flowJSON').val()!=""){flowpanel.clearData();flowpanel.loadData($.parseJSON($('#x_flowJSON').val()));alert("加载流程图成功");}flowpanel.setTitle($('#x_flowname').val());$('#flowpanel').css('backgroundColor','silver');$('#flowpanel').css('borderColor','silver');var obj = flowpanel.exportData();flowpanel.onExpandClick=function(){if(curnode==null) return;var x=(curnode.offset().left+parseInt(curnode.css('width'),10))+'px';var y=curnode.offset().top+'px';tframe.css('left',x);tframe.css('top',y);tframe.attr('src','test_server.aspx?cid='+$('#x_cid').val()+'&nid='+curnode.selector.substring(1));tframe.css('display',(tframe.css('display')=='none'?'':'none'));}flowpanel.onBtnSaveClick=function(){$('#x_flowJSON').val(JSON.stringify(this.exportData()));$('#updflow').click();}flowpanel.onItemFocus=function(id,type){flowpanel.focusItem(id,false);curnode=$("#"+id);tframe.css('display','none');}});</script>
设置审批人信息

页面名称为test_server.aspx,在流程图主功能的JS代码部分有体现, 本示例代码包含后端、前端及 JS 代码,代码如下:

<%@ Page Language="C#" AutoEventWireup="true" enableEventValidation="false" MaintainScrollPositionOnPostback="true"  ValidateRequest="FALSE" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %><script language="C#" runat="server">public CosysJaneCommonAPI.CODAL dal = new CosysJaneCommonAPI.CODAL();public DateTime dt = DateTime.Now;void Page_load(Object sender, EventArgs e){dal.RunAt = Form;if (Page.IsPostBack == true) return;ArrayList paras = new ArrayList();dal.simpledatalist("select cid,nickname,name from accounts ", null, "cid", "name", sprlist, false, "", "");dal.simpledatalist("select cid,'抄送' name from accounts ", null, "cid", "name", spr2list, false, "", "");dal.RowsCount = 0;dal.ErrorMessage = "";string cid = Request.QueryString["cid"];string nodeid = Request.QueryString["nid"];paras.Clear();paras.Add(new SqlParameter("cid", cid));paras.Add(new SqlParameter("nodeid", nodeid));object rv = dal.GetDataSet("select AccountCid,nodeId,role from cc_flowNodeAccounts where projectCid=@cid and nodeId=@nodeid", paras);if (dal.RowsCount > 0){DataTable dt = (rv as DataSet).Tables[0];for (int i = 0; i < dt.Rows.Count; i++){string accountid = dt.Rows[i]["AccountCid"].ToString();string role = dt.Rows[i]["role"].ToString();ListItem li = sprlist.Items.FindByValue(accountid);if (li!=null){li.Selected = true;if(role=="抄送"){spr2list.Items.FindByValue(accountid).Selected = true;}}}}}protected void saveflow_Click(object sender, EventArgs e){string cid = Request.QueryString["cid"];string nodeid = Request.QueryString["nid"];ArrayList paras = new ArrayList();paras.Clear();paras.Add(new SqlParameter("cid", cid));paras.Add(new SqlParameter("nodeid", nodeid));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("delete cc_flowNodeAccounts where projectCid=@cid and nodeId=@nodeid", paras);for (int i = 0; i < sprlist.Items.Count; i++){ListItem li = sprlist.Items[i];if (li.Selected==true){paras.Clear();paras.Add(new SqlParameter("projectCid", cid));paras.Add(new SqlParameter("AccountCid", li.Value));paras.Add(new SqlParameter("nodeid", nodeid));paras.Add(new SqlParameter("role", (spr2list.Items[i].Selected==true?"抄送":"决策")  ));paras.Add(new SqlParameter("descript", li.Text));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("insert into cc_flowNodeAccounts(projectCid,AccountCid,nodeId,role,descript) values(@projectCid,@AccountCid,@nodeid,@role,@descript) ", paras);Response.Write(dal.ErrorMessage);}}Alert(Form, "保存数据信息完成!");}protected void updflow_Click(object sender, EventArgs e){ArrayList paras = new ArrayList();paras.Clear();paras.Add(new SqlParameter("cid", x_cid.Text));}protected void tooltab_SelectedIndexChanged(object sender, EventArgs e){spr.Style["display"] = "none";sortnode.Style["display"] = "none";if (tooltab.SelectedValue == "0"){spr.Style["display"] = "";}else if (tooltab.SelectedValue == "1"){sortnode.Style["display"] = "";}}void SortRow(Object sender, EventArgs e){Newtonsoft.Json.Linq.JObject jsonObj = Newtonsoft.Json.Linq.JObject.Parse(x_flowJSON.Text);string cid = Request.QueryString["cid"];ArrayList paras = new ArrayList();paras.Clear();paras.Add(new SqlParameter("cid", cid));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("delete cc_flowNodes where projectCid=@cid ", paras);string[] la = sortstate1.Text.Split(',');int added = 0;for (int i = 0; i < la.GetLength(0); i++){if (la[i] != ""){paras.Clear();paras.Add(new SqlParameter("projectCid", cid));paras.Add(new SqlParameter("parentNodeId",(i==0?cid:la[i-1])) );paras.Add(new SqlParameter("nodeId", la[i]));paras.Add(new SqlParameter("nodeName", jsonObj["nodes"][la[i]]["name"].ToString()));paras.Add(new SqlParameter("sortid", i+1));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("insert into cc_flowNodes(projectCid,parentNodeId,nodeId,nodeName,sortid) values(@projectCid,@parentNodeId,@nodeId,@nodeName,@sortid) ", paras);if (dal.RowsCount > 0){added++;}}}paras.Clear();paras.Add(new SqlParameter("cid", cid));paras.Add(new SqlParameter("flowJSON", x_flowJSON.Text));paras.Add(new SqlParameter("nodeCount", added));dal.RowsCount = 0;dal.ErrorMessage = "";dal.ExecDbScripts("update cc_flow set flowJSON=@flowJSON,nodeCount=@nodeCount where cid=@cid ", paras);if (dal.RowsCount > 0){}else{Alert(Form, "保存流程数据信息失败!");return;}Alert(Form,"保存排序信息完毕!");}public void Alert(Control updatePanel, string msg){msg = msg.Replace("\r\n", "").Replace("'", "\\'");ScriptManager.RegisterClientScriptBlock(updatePanel, this.GetType(), "", "alert('" + msg + "')", true);}
</script>        <!DOCTYPE html>
<html lang="cn" >
<head><meta charset="UTF-8"><title></title>
</head><body style=" background-color:Gray"><form runat="server"><div style=" display:flex"><asp:RadioButtonList ID="tooltab" AutoPostBack="true"   Font-Names="微软雅黑" RepeatDirection="Horizontal" runat="server" onselectedindexchanged="tooltab_SelectedIndexChanged" ><asp:ListItem Value="0" Text="审批人" Selected="True"></asp:ListItem><asp:ListItem Value="1" Text="节点排序" ></asp:ListItem></asp:RadioButtonList></div><asp:Panel ID="spr" runat="server" Visible="true" BackColor="Silver"  ><div style=" display:flex"><asp:CheckBoxList ID="sprlist" runat="server" Height="100px" ForeColor="White" Width="134px"></asp:CheckBoxList><asp:CheckBoxList ID="spr2list" runat="server" Height="100px" BackColor="Gray" ForeColor="Silver" Width="134px"></asp:CheckBoxList><asp:Button ID="updflow"  Text="更新项目" style=" display:none" runat="server" onclick="updflow_Click" ></asp:Button><asp:TextBox ID="x_cid" style=" display:none" ReadOnly="true" runat="server"></asp:TextBox></div><div style=" display:flex"><asp:Button ID="saveflow" style=" display:none1" Text="保存审批人" runat="server" onclick="saveflow_Click"></asp:Button></div></asp:Panel><asp:Panel ID="sortnode" runat="server" Visible="true" style="display:none" BackColor="Silver"><table border="0" width="100%" cellspacing="0" cellpadding="0" id="table1"><tr><td valign="top"><div align="center"><table border="0" width="94%" cellspacing="0" cellpadding="0" id="table2"><tr><td align="left" valign="top"><asp:listbox id="funclist" ondblclick="SetValues(this)" style="border: 1px outset #6699FF; background-color: #FFFFFF;" Runat="server"Height="328px" Width="405px" Font-Names="微软雅黑"/></td><td><p align="center"><input id="moveUp" onclick="moveSelected(document.getElementById('funclist'), false)" type=button style="font-family:微软雅黑;" value="上移"/></p><p align="center"><input id="moveDown" onclick="moveSelected(document.getElementById('funclist'), true)" type=button style="font-family:微软雅黑;" value="下移"/></p><p  align="center"><input id="moveDown0" onclick="sortfunc()" type="button" value="保存"  style="font-family:微软雅黑;"/></p></td></tr></table></div></td></tr></table></asp:Panel>
<asp:TextBox ID="sortstate"  Text="" style="display:none" Runat=server/>
<asp:TextBox ID="sortstate1"  Text="" style="display:none" Runat="server"/>
<asp:Button ID="sortbtn" Text="sort" OnClick="SortRow" style="display:none" Runat="server"/><asp:TextBox ID="x_flowJSON" Rows="10" style="display:none"  width="100%" TextMode="MultiLine" runat="server"></asp:TextBox></form>
</body>
</html>
<script language="javascript" type="text/javascript">form = document.forms[0];function sortfunc() {if (!confirm('您确认保存排序结果吗?')) {return;}form.sortstate1.value = "";for (var i = 0; i < form.funclist.length; i++) {var _id = form.funclist.options[i].value;flowpanel.$nodeData[_id].sortid = i;form.sortstate1.value += _id + ",";}//  return;form.sortstate.value = "1";var obj = flowpanel.exportData();form.x_flowJSON.value = JSON.stringify(obj);form.sortbtn.click();}function AddListBoxOption(obj, _text, _value) {newOption = document.createElement("OPTION");newOption.text = _text;newOption.value = _value;obj.options.add(newOption);}function moveSelected(select, down) {if (select.selectedIndex != -1) {if (down) {if (select.selectedIndex != select.options.length - 1)var i = select.selectedIndex + 1;elsereturn;}else {if (select.selectedIndex != 0)var i = select.selectedIndex - 1;elsereturn;}var swapOption = new Object();swapOption.text = select.options[select.selectedIndex].text;swapOption.value = select.options[select.selectedIndex].value;swapOption.selected = select.options[select.selectedIndex].selected;//    swapOption.defaultSelected = select.options[select.selectedIndex].defaultSelected;for (var property in swapOption)select.options[select.selectedIndex][property] = select.options[i][property];for (var property in swapOption)select.options[i][property] = swapOption[property];}}function jsonSort(array, field, reverse) {//数组长度小于2 或 没有指定排序字段 或 不是json格式数据if (array.length < 2 || !field || typeof array[0] !== "object") return array;//数字类型排序if (typeof array[0][field] === "number") {array.sort(function (x, y) { return x[field] - y[field] });}//字符串类型排序if (typeof array[0][field] === "string") {array.sort(function (x, y) { return x[field].localeCompare(y[field]) });}//倒序if (reverse) {array.reverse();}return array;}var flowpanel = (window.parent.flowpanel);window.onload = function () {var obj = flowpanel.exportData();form.x_flowJSON.value = JSON.stringify(obj);var nodelist = document.getElementById('funclist');nodelist.length = 0;var sortid = 0;var obj2 = new Array();for (var i in obj.nodes) {flowpanel.$nodeData[i].id = i;obj2.push(flowpanel.$nodeData[i]);}var obj3 = jsonSort(obj2, 'sortid', false);for (var j = 0; j < obj3.length;j++ ) {flowpanel.$nodeData[obj3[j].id].sortid = sortid;AddListBoxOption(nodelist, obj3[j].name, obj3[j].id);sortid++;}}</script>
运行结果演示

代码正常运行后如下图所示:

点击某一节点,点击控制栏最后的设置图标,会提供选择审批人的操作界面,如下图所示:

总结

关于 GooFlow 的引用,请下载我的资源:

https://download.csdn.net/download/michaelline/89601233

CosysJaneCommonAPI.CODAL 类的 dal.simpledatalist 方法需要在实际中自行改造,可参考我的文章:

《C# Web控件与数据感应之 ListControl 类》

CosysJaneCommonAPI.CODAL 类的 dal.GetDataSet 方法需要在实际中自行改造,可参考我的文章:

CosysJaneCommonAPI.CODAL 类的 dal.ExecDbScripts 方法需要在实际中自行改造,可参考我的文章:

《C#利用IDbCommand实现通用数据库脚本执行程序》

代码这里仅供大家参考,欢迎大家评论指教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/391756.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring File Storage(文件的对象存储)框架基本使用指南

概述 本文仅作为快速入门&#xff0c;深入学习及使用详见官网 云存储 在开发过程当中&#xff0c;会使用到存文档、图片、视频、音频等等&#xff0c;这些都会涉及存储的问题&#xff0c;文件可以直接存服务器&#xff0c;但需要考虑带宽和存储空间&#xff0c;另外一种方式…

漏洞挖掘 | src中一次证书站有趣的SQL注入

一、确定站点 按照以前文章中提到的寻找可进站测试的思路&#xff0c;找到了某证书站的一处站点&#xff0c;通告栏中写明了初始密码的结构&#xff0c;因此我们可通过信息搜集进入该站点(可以考虑去搜集比较老的学号&#xff0c;因为这样的账号要么被冻结&#xff0c;要么就是…

AMD Product Specifications - AMD 产品规格汇总

AMD Product Specifications - AMD 产品规格汇总 1. Desktop, Laptop and Workstation Processor Specifications (台式处理器、笔记本电脑处理器和工作站处理器规格)2. Server Processor Specifications (服务器处理器规格)3. Embedded Processor Specifications (嵌入式处理器…

土耳其射击运动员尤素夫迪凯克在巴黎奥运会上成为互联网热门人物

这名51岁的男子以自己的方式获得了第二名,这对他的祖国来说是一个历史性的时刻。 这位冷静沉着的土耳其手枪射击运动员周二在 2024 年巴黎奥运会上获得银牌&#xff0c;在网上吸引了众多粉丝。 尤素夫迪克与他的搭档塞夫瓦尔伊莱达塔尔汉在混合团体 10 米气手枪比赛中获得第二…

jupyter notebook安装

1.安装 pip install notebook 2.显示配置文件&#xff1a; jupyter notebook --generate-config 3.修改代码路径&#xff1a; 编辑配置文件C:\Users\a\.jupyterjupyter_notebook_config.py 4.运行 jupyter notebook 会自动弹出http://localhost:8888/tree

QT 笔记

HTTPS SSL配置 下载配置 子父对象 QTimer *timer new QTimer; // QTimer inherits QObject timer->inherits("QTimer"); // returns true timer->inherits("QObject"); // returns true timer->inherits("QAbst…

保形分位数回归(CQR)

目录 简介1 介绍提纲式总结 分位数回归从数据中估计分位数 3 共性预测4 保形分位数回归(CQR)两个定理 6 实验7 结论 简介 保形预测是一种构造在有限样本中获得有效覆盖的预测区间的技术&#xff0c;无需进行分布假设。尽管有这种吸引力&#xff0c;但现有的保形方法可能是不必…

【文心智能体】梗图七夕版,一分钟让你看懂如何优化prompt,以及解析低代码工作流编排实现过程和零代码结合插件实现过程,依然是干货满满,进来康康吧

目录 背景什么是梗图梗图概念梗图结构 低代码开发最小运行单元大模型链提示词模板文心模板输出效果 测试工具链HTTP请求工具 梗图工具链全流程 梗图优化Prompt提示词优化后梗图结构提示词前后对比优化前效果优化后效果API接口BOS图片水印 梗图插件格式说明构思插件清单文件定义…

HTML-07.表格标签

一、要制作的表格如下 二、代码如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格标签<…

数据结构——双链表详解(超详细)

前言&#xff1a; 小编在之前已经写过单链表的创建了&#xff0c;接下来要开始双链表的讲解了&#xff0c;双链表比单链表要复杂一些&#xff0c;不过确实要比单链表更好进行实现&#xff01;下面紧跟小编的步伐&#xff0c;开启今天的双链表之旅&#xff01; 目录 1.概念和结构…

【已解决】没有密码,如何解除PPT的“只读方式”?

PPT可以设置有密码的“只读方式”&#xff0c;保护文件不被随意编辑更改。 在设置保护后&#xff0c;打开PPT时就会弹出对话框&#xff0c;提示需要“输入密码以修改或以只读方式打开”&#xff0c;也就是输入密码才能编辑修改PPT&#xff0c;如果点击“只读”也能打开文件&am…

[BJDCTF2020]Mark loves cat1

打开题目 发现这么多链接&#xff0c;以为要一点点去找功能上的漏洞。当你源代码&#xff0c;dirsearch&#xff0c;抓包等等操作之后&#xff0c;发现什么都没有。所以这题又是一道源码泄露题&#xff0c;上GItHack。扫描结果如下 http://63f29a80-e08b-43ae-a6d0-8e70fb02ea…

闪耀STIF2023国际科创节,望繁信科技荣获年度行业创新典范奖

2023年12月15日&#xff0c;望繁信科技在STIF2023第四届国际科创节暨DSC2023国际数字服务大会&#xff08;数服会&#xff09;活动评选中&#xff0c;斩获“2023年度行业创新典范”大奖。 作为科技创新与数字化服务领域最具影响力的年度盛会之一&#xff0c;STIF2023国际科创节…

目标检测——YOLOv10: Real-Time End-to-End Object Detection

YOLOv10是在YOLOv8的基础上&#xff0c;借鉴了RT-DETR的一些创新点改进出来的 标题&#xff1a;YOLOv10: Real-Time End-to-End Object Detection论文&#xff1a;https://arxiv.org/pdf/2405.14458源码&#xff1a;https://github.com/THU-MIG/yolov10 1. 论文介绍 在过去的几…

JAVA—面向对象编程高级

学习了一定基础后&#xff0c;开始更加深入的学习面向对象&#xff0c;包含static,final两个关键字&#xff0c;面向对象编程三大特征之继承和多态。以及对于抽象类&#xff0c;内部类&#xff0c;接口&#xff0c;枚举&#xff0c;泛型的学习。 目录 1.static &#xff08;…

原神自定义倒计时

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>原神倒计时</title><style>* {margin: 0;padding: 0;box-sizing: border-box;user-select: none;body {background: #0b1b2c;}}header {…

Javase--Date

1.Date简介 Date的学习: 1. java.util包下的类 2.用于日期、时间的描述 3. 实际上时距离一个固定时间点1970年1月1日00:00:00的毫秒数 4.我们常用的是格林威治时间:GMT UTC:世界调整时间 5.固定时间点:说的其实是本初子午线的时间。因此北京时间是1970年1月1日8:00:…

c++ 容器 vector

vector的意思就是向量&#xff0c;就是一个顺序表的意思&#xff0c;这个顺序表可以存任意的类型&#xff0c;因为其线性的内存特点&#xff0c;所以在stl里是经常被使用的存在。 vector vector既然要能储存任意的变量&#xff0c;那么就必须使用模板: 这里的T就是变量类型&a…

微信小程序之behaviors

目录 概括 Demo演示 进阶演示 1. 若具有同名的属性或方法 2. 若有同名的数据 3. 若有同名的生命周期函数 应用场景 最后 属性&方法 组件中使用 代码示例&#xff1a; 同名字段的覆盖和组合规则 概括 一句话总结: behaviors是用于组件间代码共享的特性, 类似一…

Docker简介 MacM1安装Docker

文章目录 1 Docker简介2 Docker VS 虚拟机1 Docker优势2 Docker用途 3 MacM1 下载安装Docker1 配置环境变量 4 配置Docker2 设置Docker资源3 设置Docker镜像 参考 1 Docker简介 Docker主要解决了软件开发和运行配置的问题&#xff0c;但是由于其功能的强大&#xff0c;也被应用…