Răsfoiți Sursa

处理遥信端子逻辑

liling 1 an în urmă
părinte
comite
ba9c5ef13c

+ 8 - 3
service/controllers/busAdminController.go

@@ -959,7 +959,7 @@ func (c *BusAdminController) SaveFuncFcdaRef() {
 		return
 	}
 	fcdaMgr.Model.FromFuncId = fcdainf.FuncId
-	//清除原关系
+	//清除输出端子的原关系
 	err := fcdaMgr.Delete()
 	if err != nil {
 		c.Data["json"] = c.ResultError(err.Error())
@@ -969,14 +969,19 @@ func (c *BusAdminController) SaveFuncFcdaRef() {
 	if fcda_in_ids != "" {
 		fcda_in_ids_1 := strings.Split(fcda_in_ids, ",")
 		for _, k := range fcda_in_ids_1 {
-			fcdaMgr.Model.ToFcdaId, _ = strconv.Atoi(k)
+			fcdaMgr.Model.ToFcdaId, _ = strconv.Atoi(k) //设置接收端子id
 			fcdainf, er = obj.One(fcdaMgr.Model.ToFcdaId)
 			if er != nil {
-				c.Data["json"] = c.ResultError("无效的输入端子ID")
+				c.Data["json"] = c.ResultError("无效的接收端子ID")
 				c.ServeJSON()
 				return
 			}
+			//清除接收端子的原关系
+			fcdaMgr.Model.FromFcdaId = 0
+			fcdaMgr.Delete()
 			fcdaMgr.Model.ToFuncId = fcdainf.FuncId
+			//建立新的端子关系
+			fcdaMgr.Model.FromFcdaId = fcda_id //还原输出端子id
 			err := fcdaMgr.Save()
 			if err != nil {
 				c.Data["json"] = c.ResultError(err.Error())

+ 3 - 3
service/models/bo/check_sysmodel_ied_fcda_relation.go

@@ -79,9 +79,9 @@ func (c *SysCheckModelFcdaRalationMgr) Delete() (err error) {
 	if c.Model.FromFcdaId > 0 && c.Model.ToFcdaId > 0 {
 		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and from_fcda_id=? and to_fcda_id=?", c.Model.ModelId, c.Model.FromFcdaId, c.Model.ToFcdaId).Exec()
 	} else if c.Model.FromFcdaId > 0 {
-		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and (from_fcda_id=? or to_fcda_id=?) and to_ied_code=? and goosesv=?", c.Model.ModelId, c.Model.FromFcdaId, c.Model.FromFcdaId, c.Model.ToIedCode, c.Model.Goosesv).Exec()
+		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and from_fcda_id=? and to_ied_code=? and goosesv=?", c.Model.ModelId, c.Model.FromFcdaId, c.Model.ToIedCode, c.Model.Goosesv).Exec()
 	} else if c.Model.ToFcdaId > 0 {
-		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and (from_fcda_id=? or to_fcda_id=?)", c.Model.ModelId, c.Model.ToFcdaId, c.Model.ToFcdaId).Exec()
+		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and to_fcda_id=? and to_ied_code=?", c.Model.ModelId, c.Model.ToFcdaId, c.Model.FromIedCode).Exec()
 	} else if c.Model.FromFuncId > 0 {
 		_, err = db.Raw("delete from t_data_model_fcda_ref where model_id=? and from_func_id=?", c.Model.ModelId, c.Model.FromFuncId).Exec()
 	} else if c.Model.FromIedCode != "" {
@@ -128,7 +128,7 @@ func (c *SysCheckModelFcdaRalationMgr) GetList() ([]orm.Params, error) {
 
 func (c *SysCheckModelFcdaRalationMgr) GetModelAllFcdaRef() (map[string][]orm.Params, error) {
 	db := orm.NewOrm()
-	sql := "select r1.*,f1.fcda_name from_fcda_name,f1.fcda_match_exp from_fcda_match_exp,f2.fcda_name to_fcda_name,f2.fcda_match_exp to_fcda_match_exp from t_data_model_fcda_ref r1 left join t_data_model_func_fcda f1 on r1.from_fcda_id=f1.id left join t_data_model_func_fcda f2 on r1.to_fcda_id=f2.id where r1.model_id=? "
+	sql := "select r1.*,(select func_name from t_data_model_func_def where id=f1.func_id) from_func_name,(select func_name from t_data_model_func_def where id=f2.func_id) to_func_name,f1.fcda_name from_fcda_name,f1.fcda_match_exp from_fcda_match_exp,f2.fcda_name to_fcda_name,f2.fcda_match_exp to_fcda_match_exp from t_data_model_fcda_ref r1 left join t_data_model_func_fcda f1 on r1.from_fcda_id=f1.id left join t_data_model_func_fcda f2 on r1.to_fcda_id=f2.id where r1.model_id=? "
 	rowset := []orm.Params{}
 	sqlParamters := []interface{}{c.Model.ModelId}
 	_, err := db.Raw(sql, sqlParamters).Values(&rowset)

+ 108 - 2
service/models/bo/checktools_area.go

@@ -636,9 +636,17 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 				iedname := tools.IsEmpty(ied["ied_name"])
 				extreflist := getIedExtRefs(iedname)
 				for outiedname, refrow := range outiedlist {
+					iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
+					outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
 					outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
 					//检查是否有错误和缺失的端子
+					hasYaoXinFunc := false //是否具备遥信功能
 					for _, r := range refrow {
+						//判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
+						//遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致,以及是否有缺失和多余的遥信端子
+						if strings.Contains(tools.IsEmpty(r["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r["from_func_name"]), "遥信") {
+							hasYaoXinFunc = true
+						}
 						extref_name := tools.IsEmpty(r["to_fcda_name"])
 						fcda_name := tools.IsEmpty(r["from_fcda_name"])
 						extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
@@ -728,6 +736,9 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						fcda_name := ""
 						isHave := false
 						for _, r1 := range refrow { //设计的端子关系
+							if strings.Contains(tools.IsEmpty(r1["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r1["from_func_name"]), "遥信") {
+								hasYaoXinFunc = true
+							}
 							extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
 							rex, err := regexp.Compile(extref_name_exp)
 							if err != nil {
@@ -741,8 +752,6 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 							}
 						}
 						if !isHave {
-							iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
-							outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
 							parse_result := fmt.Sprintf("间隔%s的装置%s端子%s在设计中不存在", area_name, iedname, extref_name)
 							daname := ""
 							if r.DaName != "" {
@@ -771,6 +780,58 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 							scdNodeRule.AppendFcdaCheckResult(re)
 						}
 					}
+					if hasYaoXinFunc {
+						//遥信端子检查:仅根据scd实际配置检查其双方端子的doi名称是否相同
+						scdMgr := new(ScdMgr)
+						yx := scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
+						if len(yx) > 0 {
+							for extref, doiDesc := range yx {
+								if extref.IedName != outiedname {
+									//非当前输入装置的,不处理
+									continue
+								}
+								daname := ""
+								if extref.DaName != "" {
+									daname = "." + extref.DaName
+								}
+								//获取输出端端子名称
+								outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
+								if outFcdaDoi == nil {
+									//端子缺失
+									parse_result := fmt.Sprintf("间隔%s的装置%s端子%s的关联端子不存在", area_name, iedname, doiDesc)
+									re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
+										"ied_name":      iedname,
+										"ied_desc":      iedObj.Desc,
+										"out_ied_name":  outiedname,
+										"out_ied_desc":  outIedObj.Desc,
+										"fcda_desc":     doiDesc,
+										"fcda_addr":     extref.IntAddr,
+										"out_fcda_desc": "",
+										"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
+										"error_type":    "3",
+									}
+									//检查未通过
+									scdNodeRule.AppendFcdaCheckResult(re)
+								} else if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
+									//关联错误
+									parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, outiedname, outFcdaDoi.(*node_attr.NDOI).Desc)
+									re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
+										"ied_name":      iedname,
+										"ied_desc":      iedObj.Desc,
+										"out_ied_name":  outiedname,
+										"out_ied_desc":  outIedObj.Desc,
+										"fcda_desc":     doiDesc,
+										"fcda_addr":     extref.IntAddr,
+										"out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
+										"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
+										"error_type":    "2",
+									}
+									//检查未通过
+									scdNodeRule.AppendFcdaCheckResult(re)
+								}
+							}
+						}
+					}
 				}
 			}
 		}
@@ -879,6 +940,29 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 		volMap["middle"] = volRows[1]["vol"].(string)           //中压电压等级
 		volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
 	}
+
+	var getIedByDesc = func(iedinfo map[string]orm.Params, desc string) (string, string) {
+		scdParseMgr := new(ScdParse)
+		scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
+		for vn, row := range iedinfo {
+			v := tools.IsEmpty(row["ied_desc"])
+			if v == "" {
+				if scdXmlObj == nil {
+					return "", ""
+				}
+				scdNode := new(ScdNode)
+				ied := scdNode.GetIed(scdXmlObj, "", vn)
+				if ied == nil {
+					return "", ""
+				}
+				v = ied.Desc
+			}
+			if strings.Contains(v, desc) {
+				return v, vn
+			}
+		}
+		return "", ""
+	}
 	//判断是否将各电压等级的保护装置合并还是分开的间隔
 	//如果存在高中低压的保护装置,则说明是分开的主变间隔
 	//isMarge := true // 默认为合并的主变间隔
@@ -887,6 +971,14 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 		if tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "T" {
 			continue
 		}
+		//判断主变保护是否是按电压等级分开配置的模型
+		/*
+			if strings.Contains(iedtypes, "PT#H") || strings.Contains(iedtypes, "PT#M") || strings.Contains(iedtypes, "PT#L") {
+				h, m, l := c.getIedListByVol("PT", ieds, volMap)
+			} else {
+				pl_iedname := tools.IsEmpty(row["ied_name"])
+			}
+		*/
 		//pmIedName := ""
 		//mmIedName := ""
 		pl_iedname := tools.IsEmpty(row["ied_name"])
@@ -907,6 +999,20 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 		insvalues := []string{}
 		inAreaIedName := pl_iedname
 		insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "T"))
+		//判断间隔是否需要包含差动装置
+		if strings.Contains(iedtypes, "PT#C") {
+			ieddesc, iedname := getIedByDesc(ieds, "差动")
+			if strings.Contains(ieddesc, "差动") {
+				insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, iedname, "P", "TC"))
+			}
+		}
+		//判断间隔是否需要包含本体保护装置
+		if strings.Contains(iedtypes, "PT#0") {
+			ieddesc, iedname := getIedByDesc(ieds, "本体")
+			if strings.Contains(ieddesc, "本体") {
+				insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, iedname, "P", "T0"))
+			}
+		}
 		//合智一体IMT/MIT,分高中低压
 		h, m, l := c.getIedListByVol("IMT", ieds, volMap)
 		h = append(h, m...)

+ 4 - 3
service/models/bo/scd_area.go

@@ -48,6 +48,7 @@ type t_area_ied_relation struct {
 	IedId   int64
 	IedName string
 	IedType string
+	IedDesc string
 	PType   string //归属设备类型
 	Vol     string //电压编码
 	PCode   string //归属设备编码
@@ -320,7 +321,7 @@ func (c *ScdAreaMgr) ParseBay(substation_id int, lst []*node_attr.NVoltage) {
 				logger.Logger.Error(err, fmt.Sprintf("SQL:%s", sql))
 			} else {
 				//创建ied与间隔关联关系
-				relCols := "insert into t_area_ied_relation(scd_id, area_id,ied_id,ied_name,ied_type,p_type,vol,p_code,ied_no)values"
+				relCols := "insert into t_area_ied_relation(scd_id, area_id,ied_id,ied_name,ied_desc,ied_type,p_type,vol,p_code,ied_no)values"
 				relValues := []string{}
 				for _, bayitem := range volitem.Bay {
 					relValues = []string{}
@@ -356,7 +357,7 @@ func (c *ScdAreaMgr) ParseBay(substation_id int, lst []*node_attr.NVoltage) {
 									vol = "999"
 								}
 							}
-							relValues = append(relValues, fmt.Sprintf("(%d,%s,%d,'%s','%s','%s','%s','%s','%s')", c.ScdId, areaid, iedItem.NodeId, iedItem.Name, iedtype, ptype, vol, pcode, iedno))
+							relValues = append(relValues, fmt.Sprintf("(%d,%s,%d,'%s','%s','%s','%s','%s','%s','%s')", c.ScdId, areaid, iedItem.NodeId, iedItem.Name, iedItem.Desc, iedtype, ptype, vol, pcode, iedno))
 						}
 						if len(relValues) == 0 {
 							continue
@@ -480,7 +481,7 @@ func (c *ScdAreaMgr) AppendIedNode(scdId, iedId int64, name, str string) {
 			}
 		}
 		c.CacheLock.Unlock()
-		rel := t_area_ied_relation{AreaId: areaid, IedId: iedId, IedName: name, IedType: iedtype, PType: ptype, Vol: vol, PCode: pcode, IedNo: iedno, ScdId: scdId}
+		rel := t_area_ied_relation{AreaId: areaid, IedId: iedId, IedName: name, IedDesc: str, IedType: iedtype, PType: ptype, Vol: vol, PCode: pcode, IedNo: iedno, ScdId: scdId}
 		db.Insert(&rel)
 		//logdesc := fmt.Sprintf("添加间隔,操作数据:%+v", rel)
 		//new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Low, logdesc, c.UserInfo)

+ 49 - 0
service/models/bo/scd_mgr.go

@@ -1632,6 +1632,55 @@ func (c *ScdMgr) GetYcYkYmMap(scdXmlObj *node_attr.SCL, iedname string) (yc map[
 	return targetYaoCe, targetYaoXin, targetYaoMai
 }
 
+//获取指定IED下遥信接收端子
+func (c *ScdMgr) GetYxExtref(scdXmlObj *node_attr.SCL, scdid int64, iedname string) map[*node_attr.NExtRef]string {
+	result := map[*node_attr.NExtRef]string{}
+	targetIedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
+	mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
+	mapTargetLDoType := c.GetDOType(scdXmlObj)
+
+	tmpdata, _ := GlobalNodeMap.Load(scdid)
+	nodeCacheMap := tmpdata.(map[int64]NodeCacheMap)
+	scdNode := new(ScdNodeRule)
+	scdNode.scdXmlObject = scdXmlObj
+	for _, ap := range targetIedObj.AccessPoint {
+		if ap.Server == nil {
+			continue
+		}
+		for _, ld := range ap.Server.LDevice {
+			if ld.LN0 != nil && ld.LN0.Inputs != nil {
+				for _, extref := range ld.LN0.Inputs.ExtRef {
+					doi := scdNode.IedIntAddrExist(iedname, extref.IntAddr)
+					if doi == nil {
+						continue
+					}
+					doiObj := doi.(*node_attr.NDOI)
+					lnnode := nodeCacheMap[nodeCacheMap[doiObj.NodeId].ParentNodeId]
+					lnType := lnnode.ObjAddr.(*node_attr.NLN).LnType
+					if lnType != "" {
+						if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
+							for _, doitem := range lnnodetpye.DO {
+								if doitem.Name == doiObj.Name {
+									dotype := doitem.Type
+									if dotypeobj, h := mapTargetLDoType[dotype]; h {
+										cdctype := new(ScdMgr).GetDoTypePointType(dotypeobj, nil)
+										if cdctype == "YX" {
+											result[extref] = doiObj.Desc
+										}
+									}
+									break
+								}
+							}
+						}
+					}
+				}
+				break
+			}
+		}
+	}
+	return result
+}
+
 //获取定值DOType集合
 //规则:模型模板中,DOType包含cdc为"SPG", "ING", "ASG", "STG", "ENG", "ORG",”TSG”,”CSG”,”CUG”,”VSG”,”CURVE”
 //同时DOType的DA子节点中含有name为setVal或setMag元素的DOType