/// <summary> /// 添加新的节点 /// </summary> /// <returns></returns> public ActionResult AddNewNode(string CallBackIndexView = "Index") { //获取合法的新节点ID int targetDefaultNodeId = 0; lock (((ICollection)ConfigNodeList).SyncRoot) { do { targetDefaultNodeId++; } while (ConfigNodeList.ContainsKey(targetDefaultNodeId.ToString())); //添加默认的数据 ResponseNodeConfig newOne = new ResponseNodeConfig(targetDefaultNodeId.ToString()); DefaultDealingHandlerConfig dealing = new DefaultDealingHandlerConfig() { DataType = DataTypes.Text, RawData = "呈現的文本" }; newOne.DealingHandlerConfig = dealing; newOne.DoneHandlerConfig = new DefaultDoneHandlerConfig(); ConfigNodeList.Add(newOne.NodeID, newOne); //写入到配置文件 ResponseConfiguration.SaveConfig_ResponseChain(ConfigNodeList.Values.ToArray()); ViewData["CurrentEditedNode"] = newOne; //进入编辑状态 Session["AdvantanceConfig_CustomHandler_Result"] = new Dictionary <Type, IConfigClassOfCustomHandler>(); //每次进去编辑状态,清空自定义处理器的参数配置结果 } LoadDatas(); ViewBag.CallBackIndexView = CallBackIndexView; return(View("Index")); }
/// <summary> /// 保存单个节点的配置 /// </summary> private void SaveOneConfig(ResponseNodeConfig configNode, string oldNodeId) { lock (((ICollection)ConfigNodeList).SyncRoot) { //删除旧的 if (ConfigNodeList.ContainsKey(oldNodeId)) { ConfigNodeList.Remove(oldNodeId); } //新增 ConfigNodeList[configNode.NodeID] = configNode; } //写入到配置文件 ResponseConfiguration.SaveConfig_ResponseChain(ConfigNodeList.Values.ToArray()); }
/// <summary> /// 将节点信息转化为Json格式 /// </summary> /// <param name="nodeConfig">节点配置</param> /// <param name="pID">节点ID(用于ZTree)</param> /// <param name="parentID">父节点ID(用于ZTree)</param> /// <returns>Json描述</returns> private string GetTreeStruct_Helper_Convert2Json(ResponseNodeConfig nodeConfig, string pID, string parentID, bool MarkFlag_Repeat = false) { //格式:{ id: 1, pId: 0, name: "父节点 1", open: true ,Editable:true, Deleteable:true }, string currentNodeId = nodeConfig.NodeID; string summary = nodeConfig.GetSummary(); string json = BuildTreeNodeJson(pID, parentID, MarkFlag_Repeat ? (summary + " (鏈路迴圈的節點,停止展開)") : (summary), currentNodeId, true, true, currentNodeId == ConstString.ROOT_NODE_ID ? false : true, //根节点不允许删除 MarkFlag_Repeat ? "#ECFFE8" : "#0" ); return(json); }
/// <summary> /// 生成树的枝干 /// </summary> /// <param name="nodeConfig">节点配置</param> /// <param name="pID">节点ID(用于ZTree)</param> /// <param name="parentID">父节点ID(用于ZTree)</param> /// <param name="parentID">记录单条链路出现过的ID<para/>(当FindSubNodes标记为False时,此集合不关注,此情况下可以传NULL)</param> /// <param name="FindSubNodes">行为:是否展开处理子节点</param> /// <param name="ShowNextNodeThenStopFindSubNodes">最后呈现多一次子节点,后续不再呈现(目前Obsolete此属性,请勿使用)</param> /// <returns></returns> private string GetTreeStruct_Helper_GenerateBranch(ResponseNodeConfig nodeConfig, string pID, string parentID, HashSet <string> usedIDs, bool FindSubNodes = true, bool ShowNextNodeThenStopFindSubNodes = false) { //创建当前节点的信息 string json = GetTreeStruct_Helper_Convert2Json(nodeConfig, pID, parentID); //当前节点ID string currentNodeId = nodeConfig.NodeID; usedIDs.Add(currentNodeId); //记录:该节点属于"有父亲关联",非孤儿状态(断链状态) UsefulNodes.Add(currentNodeId); //处理子节点们 if (FindSubNodes == true && nodeConfig.DealingHandlerConfig is TextMenuHandlerConfig) { StringBuilder jsonSub = new StringBuilder(); int pID_Index = 0; TextMenuHandlerConfig menus = (TextMenuHandlerConfig)nodeConfig.DealingHandlerConfig; foreach (var menu in menus.Menus) { //获得目标子节点的Config string subID = menu.Value.ToString(); ResponseNodeConfig targetSubConfig = GetTreeStruct_Helper_GetConfigByNodeId(subID); if (targetSubConfig == null) { continue; } #region 树形结构的过滤 //## subID指定"根节点",只显示节点信息,不再呈现子节点们 if (subID == ConstString.ROOT_NODE_ID) { //jsonSub.AppendLine(GetTreeStruct_Helper_GenerateBranch(targetSubConfig, currentNodeId, null, false)); //3:false,不再展开呈现子节点 jsonSub.AppendLine(GetTreeStruct_Helper_Convert2Json(targetSubConfig, pID + "." + pID_Index++, pID, true)); continue; } #region 准备废弃 /* 考虑之后,还是不再呈现子节点的效果比较好,下面方案先注释。 */ /* * * //## 最后呈现多一次子节点,后续不再呈现 * if (ShowNextNodeThenStopFindSubNodes) * { * jsonSub.AppendLine(GetTreeStruct_Helper_GenerateBranch(targetSubConfig, currentNodeId, false)); //3:false,不再展开呈现子节点 * continue; * } * //## 子节点如果是TextMenuHandler,当开始重复时,标记为“最后呈现多一次子节点,后续不再呈现”,然后递归处理 //3:true,呈现子节点; 4:true,如果有孙节点不再展开 * { * jsonSub.AppendLine(GetTreeStruct_Helper_GenerateBranch(targetSubConfig, currentNodeId,true,true)); * continue; * } * */ #endregion //## 子节点如果是TextMenuHandler,当开始重复时,只呈现信息但是不再展开孙节点 if (usedIDs.Contains(subID)) { //jsonSub.AppendLine(GetTreeStruct_Helper_GenerateBranch(targetSubConfig, currentNodeId, null, false)); //3:false,不再展开呈现子节点 jsonSub.AppendLine(GetTreeStruct_Helper_Convert2Json(targetSubConfig, pID + "." + pID_Index++, pID, true)); UsefulNodes.Add(subID); continue; } //## 其他情景,正常呈现节点信息 + 递归子节点 HashSet <string> currentLink_usedIDs = new HashSet <string>(usedIDs); currentLink_usedIDs.Add(currentNodeId); jsonSub.AppendLine(GetTreeStruct_Helper_GenerateBranch(targetSubConfig, pID + "." + pID_Index++, pID, currentLink_usedIDs)); #endregion } json += jsonSub.ToString(); } return(json); }
public ActionResult SaveEdit(Dictionary <string, string> parmDic) { /* Doubt: 只能序列化成 <Stirng,String>? 当使用<Stirng,dynamic>,无法为Value赋值"集合"/"JObject";会转换成无法使用的 System.Object? * * 因此这里的“DefaultNews”和 “TextMenu”, * 从View层序列化成 JsonString,然后再在Controller还原。 * 求解决方案。 */ //抽取基本数据 string targetNodeId = parmDic["NodeID"]; string NewNodeId = parmDic["NewNodeId"]; string DealingHandler = parmDic["DealingHandler"]; string DoneHandler = parmDic["DoneHandler"]; //检查ID是否重复、格式是否正确 if (targetNodeId != ConstString.ROOT_NODE_ID && targetNodeId != NewNodeId) //修改了NodeID时才检查 { if (NodeIdValidator.IsValid(NewNodeId) == false) { return(Json(new { IsSuccess = false, errorMessage = "節點ID格式不正確。必須為 x.y.z 序號格式。" })); } bool isExisted = false; lock (((ICollection)ConfigNodeList).SyncRoot) isExisted = ConfigNodeList.ContainsKey(NewNodeId); if (isExisted) { return(Json(new { IsSuccess = false, errorMessage = "修改的節點ID已經存在,不可以重複。" })); } } ResponseNodeConfig configNode = new ResponseNodeConfig(NewNodeId); StringBuilder errorMessage = new StringBuilder(); //开始根据不同类型,解析具体的数据 bool isNeedDoneHandler = true; //标记是否需要Done阶段;因为有部分Dealing处理器,处理完则跳转节点,此时不需要再配置Done。 #region DealingHandler switch (DealingHandler) { default: errorMessage.AppendLine("找不到對應的Dealing類型。"); break; case "DefaultText": { DefaultDealingHandlerConfig HandlerResult = new DefaultDealingHandlerConfig(); HandlerResult.DataType = DataTypes.Text; HandlerResult.RawData = parmDic["DealingHandler_DefaultText"]; configNode.DealingHandlerConfig = HandlerResult; } break; case "DefaultNews": { DefaultDealingHandlerConfig HandlerResult = new DefaultDealingHandlerConfig(); HandlerResult.DataType = DataTypes.News; dynamic news = Newtonsoft.Json.Linq.JObject.Parse(parmDic["DealingHandler_DefaultNews"]); HandlerResult.RawData = new ArticleCan(news.title.ToString(), news.description.ToString(), news.picUrl.ToString(), news.pageUrl.ToString()); configNode.DealingHandlerConfig = HandlerResult; } break; case "TextMenu": { TextMenuHandlerConfig HandlerResult = new TextMenuHandlerConfig(); //##提示文字 ResponseTextMessageConfig ready = new ResponseTextMessageConfig(); ready.Context = parmDic["DealingHandler_TextMenu_ReadyMessage"]; HandlerResult.ReadyMessageConfig = ready; //##菜单项 var menus = Newtonsoft.Json.Linq.JObject.Parse(parmDic["DealingHandler_TextMenu_Menus"]); foreach (var menu in menus) { string theNodeid = menu.Value["Id"].ToString().Replace("#", String.Empty); //??Json序列化时,如果Key为纯数字(即使类型是字符串),会被排序。因此这个用#前缀处理。 //有效性检查 if (NodeIdValidator.IsValid(theNodeid) == false) { errorMessage.Append(theNodeid); errorMessage.AppendLine("不是有效的節點ID格式。必須為 x.y.z 序號格式。"); break; } //重复检查(紧跟其下的目标跳转的节点ID,不能与当前节点ID一样,否则会直接循环跳转 ; 跨节点的,不限制。) if (String.Equals(NewNodeId, theNodeid, StringComparison.OrdinalIgnoreCase)) { errorMessage.Append("子節點"); errorMessage.Append(theNodeid); errorMessage.AppendLine(",不能與當前節點的ID重複。"); break; } HandlerResult.Menus.Add(new DictionaryEntry(menu.Value["data"].ToString(), theNodeid)); } configNode.DealingHandlerConfig = HandlerResult; isNeedDoneHandler = false; //标记不处理Done } break; case "CustomHandler": { CustomHandlerConfig HandlerResult = new CustomHandlerConfig(); HandlerResult.HandlerTypeName = parmDic["DealingHandler_CustomHandler"]; configNode.DealingHandlerConfig = HandlerResult; //自定义处理的参数配置 Type targetType = CustomHandlerConfig.GetICustomHandlerTypeFromCurrentDomain(HandlerResult.HandlerTypeName); bool isConfigable = typeof(ICustomHandlerConfigable).IsAssignableFrom(targetType); if (isConfigable && Session["AdvantanceConfig_CustomHandler_Result"] != null) { var dictionary = Session["AdvantanceConfig_CustomHandler_Result"] as IDictionary <Type, IConfigClassOfCustomHandler>; if (dictionary != null && dictionary.ContainsKey(targetType)) { IConfigClassOfCustomHandler configData = dictionary[targetType] as IConfigClassOfCustomHandler; if (configData != null) { //获取配置类 Type configClassType = ConfigClassOfCustomHandlerHelper.GetConfigClassType(targetType); if (configClassType != null) { //加载 XDocument xdoc = ConfigClassOfCustomHandlerHelper.LoadConfigByType(configClassType); ConfigClassOfCustomHandlerHelper.RemoveConfig(xdoc, targetNodeId); ConfigClassOfCustomHandlerHelper.UpdateConfig(xdoc, NewNodeId, configData); //保存 ConfigClassOfCustomHandlerHelper.SaveConfigByType(configClassType, xdoc); } } } } } break; } #endregion #region DoneHandler if (isNeedDoneHandler) { switch (DoneHandler) { default: errorMessage.AppendLine("找不到對應的Done類型。"); break; case "DefaultRootNode": { //DefaultDoneHandlerConfig HandlerResult = new DefaultDoneHandlerConfig(); configNode.DoneHandlerConfig = null; } break; case "DefaultTargetNode": { if (NodeIdValidator.IsValid(parmDic["DoneHandler_JumpNode"]) == false) { errorMessage.Append(parmDic["DoneHandler_JumpNode"]); errorMessage.AppendLine("不是有效的節點ID格式。必須為 x.y.z 序號格式。"); break; } DefaultDoneHandlerConfig HandlerResult = new DefaultDoneHandlerConfig(); HandlerResult.NodeId = parmDic["DoneHandler_JumpNode"]; HandlerResult.TipText = parmDic["DoneHandler_TipText"]; configNode.DoneHandlerConfig = HandlerResult; } break; } } #endregion //反馈结果 if (errorMessage.Length <= 0) { SaveOneConfig(configNode, targetNodeId); return(Json(new { IsSuccess = true })); } else { return(Json(new { IsSuccess = false, errorMessage = errorMessage.ToString() })); } }