protected void Page_Load(object sender, EventArgs e) { B_HSEdit l_BusReceiveEdit = null; B_Circulate l_BusCirculate = null; DataTable l_dtbCirculate = null; DataTable l_dtbProcessSteps = null; String l_strRegisterID = null; B_LetterReceive l_objWorkItem = null; WFBaseProcessInstance l_objProcessInstance = null; if (!Page.IsPostBack) { this.ucAttachment.UCIsEditable = false; PreviousPageUrl = Request.UrlReferrer.ToString(); l_strRegisterID = Request.QueryString[ConstString.QueryString.REGISTER_ID]; l_BusReceiveEdit = new B_HSEdit(); l_BusReceiveEdit.ID = Convert.ToInt32(l_strRegisterID); if (l_BusReceiveEdit == null) { ValidateUtility.ShowMsgBox(this.Page, FS.ADIM.OA.BLL.Common.Utility.MessageType.VbCritical, "当前的ID或者无效,或者已经被删除!"); return; } this.ucAttachment.UCTemplateName = l_BusReceiveEdit.ProcessName; PopulateField(l_BusReceiveEdit); if (String.IsNullOrEmpty(l_BusReceiveEdit.ProcessID)) { divPrompt.Visible = true; return; } l_objProcessInstance = FS.OA.Framework.WorkFlow.WFFactory.GetWF(FS.OA.Framework.WorkFlow.WFType.AgilePoint).GetAPI().GetProcInst(l_BusReceiveEdit.ProcessID); if (l_objProcessInstance != null) { m_strProcessTemplate = l_objProcessInstance.DefName; String l_strCirculateTableName = FS.ADIM.OA.BLL.Common.TableName.GetCirculateTableName(l_objProcessInstance.DefName); l_BusCirculate = new B_Circulate(l_strCirculateTableName); l_dtbCirculate = l_BusCirculate.GetCirculatesByID(l_strCirculateTableName, l_BusReceiveEdit.ProcessID, 0); gdvCirculate.DataSource = l_dtbCirculate; gdvCirculate.DataBind(); l_objWorkItem = new B_LetterReceive(); l_dtbProcessSteps = l_objWorkItem.GetStepsByProcessID(l_BusReceiveEdit.ProcessID, TableName.WorkItemsTableName.T_OA_HS_WorkItems + ((l_objProcessInstance.Status == ProcessConstString.ProcessStatus.STATUS_COMPLETED || l_objProcessInstance.Status == ProcessConstString.ProcessStatus.STATUS_CANCELED) ? "_BAK" : "")); DataView l_dtvDataView = new DataView(l_dtbProcessSteps); l_dtvDataView.RowFilter = "D_StepStatus = 'Completed'"; rptProcessDetail.DataSource = l_dtvDataView; rptProcessDetail.DataBind(); } } }
//找到下个结点 private WFManualWorkItem getNextNode(string processInstanceID) { if (String.IsNullOrEmpty(processInstanceID)) { throw new Exception("getCurrentParticipant - processInstanceID is empty"); } WFBaseProcessInstance pi = api.GetProcInst(processInstanceID); int times = 0; while (times < 30) // wait for 30 times, { if (pi.Status.Equals(WFProcessInstance.COMPLETED) || pi.Status.Equals(WFProcessInstance.CANCELLED)) { return(null); } else { string where = "WF_MANUAL_WORKITEMS.PROC_INST_ID='" + processInstanceID + "' and WF_MANUAL_WORKITEMS.STATUS in ('" + WFManualWorkItem.ASSIGNED + "','" + WFManualWorkItem.OVERDUE + "','" + WFManualWorkItem.REASSIGNED + "','" + WFManualWorkItem.PSEUDO + "')"; WFManualWorkItem[] wis = api.QueryWorkListEx(where); if (wis.Length > 0) { return(wis[0]); } else { System.Threading.Thread.Sleep(1000); // wait time unit pi = api.GetProcInst(processInstanceID); } } times++; } throw new Exception("FLOWNODE NOT FOUND(" + pi.ProcInstName + ")"); }
private String GetProcInstName(String piID) { String name = ""; IWFWorkflowService api = WFFactory.GetWF(WFType.AgilePoint).GetAPI(); WFBaseProcessInstance pi = api.GetProcInst(piID); if (pi != null) { name = string.Format("{0},{1}", pi.ProcInstName, pi.Status); } return(name); }
public static WFBaseProcessInstance GetProcInst(string PIID) { // This is sample code for console application IWFWorkflowService svc = Common.GetWorkFlowAPI(); string processInstanceID = PIID;// process instance ID WFBaseProcessInstance processInstance = null; try { //Returns an instance of WFBaseProcessInstance type. processInstance = svc.GetProcInst(processInstanceID); } catch (Exception ex) { } return(processInstance); }
public string GetActivityInstInfo(string piID, string aiID) { string html = ""; try { WorkflowService api = WFFactory.GetWF(WFType.AgilePoint).GetAPI(); WFBaseProcessInstance pi = api.GetProcInst(piID); WFManualWorkItem[] mwks = GetManualWorkItems(api, aiID); WFAutomaticWorkItem[] awks = null; if (mwks == null || mwks.Length == 0) { awks = GetAutomaticWorkItems(api, aiID); } html = RenderActivityContent(api, pi, aiID, mwks, awks); } catch (Exception) { } return(html); }
private int CountParticipantOnActivity(IWFWorkflowService api, string piID, WFBaseActivityInstance ai) { ArrayList participantList = new ArrayList(); //Retreive Activity definition to know the type of activity WFBaseProcessInstance pi = api.GetProcInst(piID); string xmlString = api.GetProcDefXml(pi.DefID); WFProcessDefinition processDef = new WFProcessDefinition(); ProcDefXmlParser xmlParser = new ProcDefXmlParser(processDef); xmlParser.Parse(xmlString); IWFActivityDefinition ad = processDef.FindActivityByName(ai.Name); WFManualActivityDefinition activityDef = null; //Get the type of activity if (ad != null && ad.GetType() == typeof(WFManualActivityDefinition)) { activityDef = (WFManualActivityDefinition)ad; } // Get manual work items for the given Activity WFAny any = WFAny.Create(ai.ID); WFQueryExpr expr = new WFQueryExpr("ACTIVITY_INST_ID", SQLExpr.EQ, any, true); WFManualWorkItem[] wks = api.QueryWorkList(expr); if (wks != null) { foreach (WFManualWorkItem wk in wks) { if (wk.Status == WFManualWorkItem.ASSIGNED || wk.Status == WFManualWorkItem.OVERDUE || wk.Status == WFManualWorkItem.COMPLETED) { if (!String.IsNullOrEmpty(wk.UserID) && !participantList.Contains(wk.UserID.ToLower())) { participantList.Add(wk.UserID.ToLower()); } } } } // if activity is Agilework of type ProcessAdaptation if (activityDef != null && activityDef.CustomProperties.Contains("Ascentn.AgileWork.Premier.ProcessAdaptation")) { //Get type of the AgileWork string activityType = api.GetCustomAttr(pi.WorkObjectID, ai.ID + "_ApprovalType") as string; //Count number of participant in case of sequential type if (activityType == "Sequential") { string activityProperties = api.GetCustomAttr(pi.WorkObjectID, ai.ID + "_ActivityProperties") as string; if (!String.IsNullOrEmpty(activityProperties)) { string[] approverInfoList = activityProperties.Split(';'); foreach (string approverInfo in approverInfoList) { string[] userInfoList = approverInfo.Split('|'); string user = userInfoList[0]; if (!String.IsNullOrEmpty(user) && !participantList.Contains(user.ToLower())) { participantList.Add(user.ToLower()); } } } } } return(participantList.Count); }
private String RenderActivityContent(WorkflowService api, WFBaseProcessInstance pi, string id, WFManualWorkItem[] mwks, WFAutomaticWorkItem[] awks) { string header = // "<DIV style=\"DISPLAY:none;OVERFLOW: auto\">\n" "<TABLE id='popupTable' align=center border=1 bordercolor=lightgrey>\n" + "<TR><td>\n" + "<TABLE style=\"background-color: #ffffcc;font-family: 宋体,Verdana,sans-serif;font-size: 12;Z-INDEX:106\" cellSpacing=\"0\" cellPadding=\"2\" border=\"0\">\n"; string footer = "</TABLE>\n" + "</TD></TR>\n" + "</TABLE>\n"; string content = ""; WFBaseActivityInstance ai = api.GetActivityInst(id); //Retreive process definition and Activity definition string xmlString = api.GetProcDefXml(pi.DefID); WFProcessDefinition processDef = new WFProcessDefinition(); ProcDefXmlParser xmlParser = new ProcDefXmlParser(processDef); xmlParser.Parse(xmlString); IWFActivityDefinition ad = processDef.FindActivityByName(ai.Name); WFManualActivityDefinition activityDef = null; if (ad != null && ad.GetType() == typeof(WFManualActivityDefinition)) { activityDef = (WFManualActivityDefinition)ad; } bool isSub = false; //zhouli ArrayList arrSub = new ArrayList(); ArrayList arrSubName = new ArrayList(); if (ai.Session > 0) { string status = ConvUtil.GetDisplayStatus(pi.Status, ai.Session, ai.TokenPos.Value, ai.Pending, ai.InStack); //zhouli string sql = string.Format(@"SELECT Proc_Inst_ID,Proc_Inst_Name FROM WF_PROC_INSTS WHERE SUPER_PROC_INST_ID='{0}'", pi.ProcInstID); DataTable dtSub = SQLHelper.GetDataTable2(sql); if (dtSub.Rows.Count > 0) { foreach (DataRow dr in dtSub.Rows) { arrSub.Add(dr["Proc_Inst_ID"].ToString()); arrSubName.Add(dr["Proc_Inst_Name"].ToString()); } } status = GetCNStatus(status); content += ConstructRow(status, ""); content += ConstructRow(null, null); if (mwks == null || mwks.Length == 0) { content += ConstructRow("开始日期:", DTFormat(ai.StartedDate)); if (ai.CompletedDate.Ticks > 0) { content += ConstructRow("完成日期:", DTFormat(ai.CompletedDate)); } if (awks != null) { Hashtable names = GetSubProcInstName(api, awks); string url = null; string procInstName = null; foreach (WFAutomaticWorkItem wk in awks) { procInstName = (string)names[wk.WorkItemID]; url = string.Format("<a href=# onclick=\"parent.showSubProcess('{0}')\">Sub Process '{1}'</a>", wk.WorkItemID, procInstName); content += ConstructRow(string.Format("#{0}", wk.Session), url); } } } //Show Mannual activity information else { ArrayList participantList = new ArrayList(); ArrayList participantStatus = new ArrayList(); //Create a list of participant involved in this activity for (int index = mwks.Length - 1; index >= 0; index--) { if (mwks[index].Status == WFManualWorkItem.ASSIGNED || mwks[index].Status == WFManualWorkItem.OVERDUE || mwks[index].Status == WFManualWorkItem.COMPLETED) { if (!String.IsNullOrEmpty(mwks[index].UserID)) { participantList.Add(mwks[index].UserID); participantStatus.Add(mwks[index].Status); } } } //Show type of activity and participant info if it AgileWork of type process adaptation if (activityDef != null && activityDef.CustomProperties.Contains("Ascentn.AgileWork.Premier.ProcessAdaptation")) { //Get type of the AgileWork string activityType = api.GetCustomAttr(pi.WorkObjectID, id + "_ApprovalType") as string; //Show type of the activity content += ConstructRow(null, null); content += ConstructRow("Activity Type:", activityType); //Add those participant who have not been assgined yet(in case of sequential type) to participantList if (activityType == "Sequential") { string activityProperties = api.GetCustomAttr(pi.WorkObjectID, id + "_ActivityProperties") as string; if (!String.IsNullOrEmpty(activityProperties)) { string[] approverInfoList = activityProperties.Split(';'); //If number of Approver is more than one, only first approver is get assigned //So add the rest approver(who have not been assigned)to the Participant List if (approverInfoList.Length > 1) { for (int i = 1; i < approverInfoList.Length; i++) { string[] userInfoList = approverInfoList[i].Split('|'); string user = userInfoList[0]; if (!String.IsNullOrEmpty(user)) { participantList.Add(user); participantStatus.Add("In Queue"); } } } } } } #region 显示人物列表 //Show participant list for the activity if (participantList.Count > 0) { content += ConstructRow("参与该任务的用户", null); for (int i = 0; i < participantList.Count; i++) { if (participantList[i].ToString().ToLower() != @"dev003\dummy")//zhouli { content += ConstructRow(participantList[i] + ":", participantStatus[i]); } } } foreach (WFManualWorkItem wk in mwks) { if (content.Length > 0) { content += ConstructRow(null, null); } if (wk.UserID.ToLower() == @"dev003\dummy") //zhouli { for (int sub = 0; sub < arrSub.Count; sub++) { //content += ConstructRow("子流程", arrSub[sub].ToString()); string url = string.Format("<a href=# onclick=\"parent.showSubProcess('{0}')\">{1}</a>", arrSub[sub].ToString(), arrSubName[sub].ToString()); content += ConstructRow("子流程", url); } } else { content += ConstructRow("会话:", wk.Session); content += ConstructRow("任务:", wk.Name); content += ConstructRow("任务处理人:", GetUserName(wk.UserID)); //zhouli content += ConstructRow("任务接收日期:", DTFormat(wk.AssignedDate)); //content += ConstructRow("过期日期:", DTFormat(wk.DueDate)); if (wk.CompletedDate.Ticks > 0) { content += ConstructRow("完成日期:", DTFormat(wk.CompletedDate)); } content += ConstructRow("状态:", wk.Status); } } #endregion } //Add custom attributes changes during this activity into content content += AddCustomAttribToContent(pi.ProcInstID, ai.StartedDate.ToString("M/d/yyyy H:mm:ss:fff tt"), ai.CompletedDate.ToString("M/d/yyyy H:mm:ss:fff tt")); //Show Process Adaptation Link only when AgileWork is of type Ascentn.AgileWork.Premier.ProcessAdaptation and not completed or cancled if (status != WFBaseActivityInstance.PASSED && status != WFBaseActivityInstance.CANCELLED && activityDef != null && activityDef.CustomProperties.Contains("Ascentn.AgileWork.Premier.ProcessAdaptation")) { // Get Process Adaptation Url from web.config string processAdaptationUrl = (String)ConfigurationManager.AppSettings["ProcessAdaptationUrl"]; string queryString = "?ProcessTemplate=" + pi.DefName + "&ProcessInstance=" + pi.ProcInstID + "&ActiveInstance=" + id; string processAdptationLink = string.Format("<a href=# onclick=\"parent.showProcessAdaptation('{0}')\">Open Process Adaptation</a>", processAdaptationUrl + queryString); //Add process adaptation link to the content content += ConstructRow(null, null); content += ConstructRow(processAdptationLink, null); } } else { content += ConstructRow("信息:", "此步骤还未流转到!"); } return(header + content + footer); }
protected void Page_Load(object sender, EventArgs e) { B_ReceiveEdit l_BusReceiveEdit = null; B_Circulate l_BusCirculate = null; DataTable l_dtbCirculate = null; DataTable l_dtbProcessSteps = null; String l_strRegisterID = null; M_ReceiveBase l_objWorkItem = null; //WFBaseProcessInstance l_objProcessInstance = null; if (!Page.IsPostBack) { this.ucAttachment.UCIsEditable = false; PreviousPageUrl = Request.UrlReferrer.ToString(); l_strRegisterID = Request.QueryString[ConstString.QueryString.REGISTER_ID]; l_BusReceiveEdit = new B_ReceiveEdit(); l_BusReceiveEdit.ID = Convert.ToInt32(l_strRegisterID); if (l_BusReceiveEdit == null) { JScript.Alert("当前的ID或者无效,或者已经被删除!"); return; } this.ucAttachment.UCTemplateName = l_BusReceiveEdit.ProcessName; PopulateReceiveField(l_BusReceiveEdit); if (String.IsNullOrEmpty(l_BusReceiveEdit.ProcessID)) { divPrompt.Visible = true; return; } WFBaseProcessInstance fp = null; fp = WFFactory.GetWF(WFType.AgilePoint).GetAPI().GetProcInst(l_BusReceiveEdit.ProcessID); //l_objProcessInstance = AgilePointWF.GetAPI().GetProcInst(); if (fp != null) { ProcessTemplate = fp.DefName; String l_strCirculateTableName = FS.ADIM.OA.BLL.Common.TableName.GetCirculateTableName(fp.DefName); l_BusCirculate = new B_Circulate(l_strCirculateTableName); l_dtbCirculate = l_BusCirculate.GetCirculatesByID(l_strCirculateTableName, l_BusReceiveEdit.ProcessID, 0); gdvCirculate.DataSource = l_dtbCirculate; gdvCirculate.DataBind(); string strTableName = TableName.WorkItemsTableName.T_OA_GS_WorkItems; switch (fp.DefName) { case ProcessConstString.TemplateName.COMPANY_RECEIVE: l_objWorkItem = new B_GS_WorkItems(); strTableName = TableName.WorkItemsTableName.T_OA_GS_WorkItems; break; default: strTableName = TableName.WorkItemsTableName.T_OA_MS_WorkItems; l_objWorkItem = new B_MergeReceiveBase(); break; } strTableName += ((fp.Status == ProcessConstString.ProcessStatus.STATUS_COMPLETED || fp.Status == ProcessConstString.ProcessStatus.STATUS_CANCELED)?"_BAK":""); l_dtbProcessSteps = l_objWorkItem.GetStepsByProcessID(l_BusReceiveEdit.ProcessID, strTableName, l_objWorkItem); DataView l_dtvDataView = new DataView(l_dtbProcessSteps); l_dtvDataView.RowFilter = "D_StepStatus = 'Completed'"; rptProcessDetail.DataSource = l_dtvDataView; rptProcessDetail.DataBind(); } } }
private String RenderActivityContent(WorkflowService api, WFBaseProcessInstance pi, string id, WFManualWorkItem[] mwks, WFAutomaticWorkItem[] awks) { string header = // "<DIV style=\"DISPLAY:none;OVERFLOW: auto\">\n" "<TABLE id='popupTable' align=center border=1 bordercolor=lightgrey>\n" + "<TR><td>\n" + "<TABLE style=\"background-color: #ffffcc;font-family: 宋体,Verdana,sans-serif;font-size: 12;Z-INDEX:106\" cellSpacing=\"0\" cellPadding=\"2\" border=\"0\">\n"; string footer = "</TABLE>\n" + "</TD></TR>\n" + "</TABLE>\n"; string content = ""; WFBaseActivityInstance ai = api.GetActivityInst(id); //Retreive process definition and Activity definition string xmlString = api.GetProcDefXml(pi.DefID); WFProcessDefinition processDef = new WFProcessDefinition(); ProcDefXmlParser xmlParser = new ProcDefXmlParser(processDef); xmlParser.Parse(xmlString); IWFActivityDefinition ad = processDef.FindActivityByName(ai.Name); WFManualActivityDefinition activityDef = null; if (ad != null && ad.GetType() == typeof(WFManualActivityDefinition)) { activityDef = (WFManualActivityDefinition)ad; } bool isSub = false; //zhouli ArrayList arrSub = new ArrayList(); ArrayList arrSubName = new ArrayList(); if (ai.Session > 0) { string status = ConvUtil.GetDisplayStatus(pi.Status, ai.Session, ai.TokenPos.Value, ai.Pending, ai.InStack); //zhouli string sql = string.Format(@"SELECT Proc_Inst_ID,Proc_Inst_Name FROM WF_PROC_INSTS WHERE SUPER_PROC_INST_ID='{0}'", pi.ProcInstID); DataTable dtSub = SQLHelper.GetDataTable2(sql); if (dtSub.Rows.Count > 0) { foreach (DataRow dr in dtSub.Rows) { arrSub.Add(dr["Proc_Inst_ID"].ToString()); arrSubName.Add(dr["Proc_Inst_Name"].ToString()); } } status = GetCNStatus(status); content += ConstructRow(status, ""); content += ConstructRow(null, null); if (mwks == null || mwks.Length == 0) { content += ConstructRow("开始日期:", DTFormat(ai.StartedDate)); if (ai.CompletedDate.Ticks > 0) { content += ConstructRow("完成日期:", DTFormat(ai.CompletedDate)); } if (awks != null) { Hashtable names = GetSubProcInstName(api, awks); string url = null; string procInstName = null; foreach (WFAutomaticWorkItem wk in awks) { procInstName = (string)names[wk.WorkItemID]; url = string.Format("<a href=# onclick=\"parent.showSubProcess('{0}')\">Sub Process '{1}'</a>", wk.WorkItemID, procInstName); content += ConstructRow(string.Format("#{0}", wk.Session), url); } } } //Show Mannual activity information else { ArrayList participantList = new ArrayList(); ArrayList participantStatus = new ArrayList(); //Create a list of participant involved in this activity for (int index = mwks.Length - 1; index >= 0; index--) { if (mwks[index].Status == WFManualWorkItem.ASSIGNED || mwks[index].Status == WFManualWorkItem.OVERDUE || mwks[index].Status == WFManualWorkItem.COMPLETED) { if (!String.IsNullOrEmpty(mwks[index].UserID)) { participantList.Add(mwks[index].UserID); participantStatus.Add(mwks[index].Status); } } } //Show type of activity and participant info if it AgileWork of type process adaptation if (activityDef != null && activityDef.CustomProperties.Contains("Ascentn.AgileWork.Premier.ProcessAdaptation")) { //Get type of the AgileWork string activityType = api.GetCustomAttr(pi.WorkObjectID, id + "_ApprovalType") as string; //Show type of the activity content += ConstructRow(null, null); content += ConstructRow("Activity Type:", activityType); //Add those participant who have not been assgined yet(in case of sequential type) to participantList if (activityType == "Sequential") { string activityProperties = api.GetCustomAttr(pi.WorkObjectID, id + "_ActivityProperties") as string; if (!String.IsNullOrEmpty(activityProperties)) { string[] approverInfoList = activityProperties.Split(';'); //If number of Approver is more than one, only first approver is get assigned //So add the rest approver(who have not been assigned)to the Participant List if (approverInfoList.Length > 1) { for (int i = 1; i < approverInfoList.Length; i++) { string[] userInfoList = approverInfoList[i].Split('|'); string user = userInfoList[0]; if (!String.IsNullOrEmpty(user)) { participantList.Add(user); participantStatus.Add("In Queue"); } } } } } } #region 显示人物列表 //Show participant list for the activity if (participantList.Count > 0) { content += ConstructRow("参与该任务的用户", null); for (int i = 0; i < participantList.Count; i++) { if (participantList[i].ToString().ToLower() != @"dev003\dummy")//zhouli content += ConstructRow(participantList[i] + ":", participantStatus[i]); } } foreach (WFManualWorkItem wk in mwks) { if (content.Length > 0) content += ConstructRow(null, null); if (wk.UserID.ToLower() == @"dev003\dummy") //zhouli { for (int sub = 0; sub < arrSub.Count; sub++) { //content += ConstructRow("子流程", arrSub[sub].ToString()); string url = string.Format("<a href=# onclick=\"parent.showSubProcess('{0}')\">{1}</a>", arrSub[sub].ToString(), arrSubName[sub].ToString()); content += ConstructRow("子流程", url); } } else { content += ConstructRow("会话:", wk.Session); content += ConstructRow("任务:", wk.Name); content += ConstructRow("任务处理人:", GetUserName(wk.UserID)); //zhouli content += ConstructRow("任务接收日期:", DTFormat(wk.AssignedDate)); //content += ConstructRow("过期日期:", DTFormat(wk.DueDate)); if (wk.CompletedDate.Ticks > 0) { content += ConstructRow("完成日期:", DTFormat(wk.CompletedDate)); } content += ConstructRow("状态:", wk.Status); } } #endregion } //Add custom attributes changes during this activity into content content += AddCustomAttribToContent(pi.ProcInstID, ai.StartedDate.ToString("M/d/yyyy H:mm:ss:fff tt"), ai.CompletedDate.ToString("M/d/yyyy H:mm:ss:fff tt")); //Show Process Adaptation Link only when AgileWork is of type Ascentn.AgileWork.Premier.ProcessAdaptation and not completed or cancled if (status != WFBaseActivityInstance.PASSED && status != WFBaseActivityInstance.CANCELLED && activityDef != null && activityDef.CustomProperties.Contains("Ascentn.AgileWork.Premier.ProcessAdaptation")) { // Get Process Adaptation Url from web.config string processAdaptationUrl = (String)ConfigurationManager.AppSettings["ProcessAdaptationUrl"]; string queryString = "?ProcessTemplate=" + pi.DefName + "&ProcessInstance=" + pi.ProcInstID + "&ActiveInstance=" + id; string processAdptationLink = string.Format("<a href=# onclick=\"parent.showProcessAdaptation('{0}')\">Open Process Adaptation</a>", processAdaptationUrl + queryString); //Add process adaptation link to the content content += ConstructRow(null, null); content += ConstructRow(processAdptationLink, null); } } else { content += ConstructRow("信息:", "此步骤还未流转到!"); } return header + content + footer; }