Browse Source

修复一些bug

liling 1 year ago
parent
commit
032dd4700e

+ 25 - 0
service/controllers/apiController.go

@@ -154,6 +154,31 @@ func (c *ApiController) GetUserToken() string {
 	return strings.TrimLeft(Authorization, "Bearer ")
 }
 
+// @Summary      正则表达式匹配验证
+// @NotAuth 不需要授权可访问
+// @Description  正则表达式匹配验证
+// @Tags         基础服务接口
+// @Accept       x-www-form-urlencoded
+// @Param        regstr query  string   true  "正则表达式"
+// @Param        str  	query  string   true  "用于匹配的目标字符串"
+// @Produce      json
+// @Success      200    status   成功
+// @Failure 	 500 	status  失败
+// @router /reg/test [get]
+func (c *ApiController) RegTest() {
+	r, err := tools.RexGroupTestMatch(c.GetString("regstr"), c.GetString("str"))
+	if err != nil {
+		c.Data["json"] = c.ResultError(err)
+	} else {
+		if !r {
+			c.Data["json"] = c.ResultError("验证未通过,请检查正则表达式是否正确")
+		} else {
+			c.Data["json"] = c.ResultOK(r, 1)
+		}
+	}
+	c.ServeJSON()
+}
+
 // @Summary      客户端心跳
 // @NotAuth 不需要授权可访问
 // @Description  客户端心跳保持,由浏览器或客户端发起请求,以表示其还处于使用中

+ 34 - 0
service/controllers/busAdminController.go

@@ -750,6 +750,40 @@ func (c *BusAdminController) GetFuncListByIedType() {
 	c.ServeJSON()
 }
 
+//	@Summary 获取SCD中装置实际配置的虚端子关系
+//	@Description  获取SCD中装置实际配置的虚端子关系
+// 	@Tags         业务管理服务
+// 	@Accept       x-www-form-urlencoded
+// 	@Produce      json
+//	@Param scd_id 	formData int64 true "SCD文件ID"
+//	@Param area_ids formData string false "指定的间隔列表,多个间隔使用逗号分隔。可以不指定,不指定时则生成全站所有装置的端子关系表"
+//	@Param ied_name formData string false "指定的装置名称。可以不指定。"
+// 	@Success     200    {object} ResultOK 成功
+// 	@Failure 	 500 	{object} ResultError  失败
+// @router /admin/scd/fcda/list [get]
+func (c *BusAdminController) GetScdIedFcdaList() {
+	scd_id, _ := c.GetInt64("scd_id")
+	if scd_id == 0 {
+		c.Data["json"] = c.ResultError("SCD文件ID不能为空!")
+		c.ServeJSON()
+		return
+	}
+	areaids := c.GetString("area_ids")
+	areaLst := []string{}
+	if areaids != "" {
+		areaLst = strings.Split(areaids, ",")
+	}
+	obj := new(bo.CheckAreaMgr)
+	lst, err := obj.MakeExtrefReport(scd_id, areaLst, c.GetString("ied_name"))
+	if err != nil {
+		c.Data["json"] = c.ResultError(err.Error())
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = c.ResultOK(lst, len(lst))
+	c.ServeJSON()
+}
+
 // @Summary 获取指定模型和装置类型的端子列表
 //	@Description  获取指定模型和装置类型的端子列表
 // 	@Tags         业务管理服务

+ 1 - 1
service/main.go

@@ -100,7 +100,7 @@ func main() {
 	}
 	//new(test.UnitTest).TestIntAddrParse("RPIT/GOINGGIO1.SPCSO1.stVal")
 	//new(test.UnitTest).TestDoiNameRex("(断路器)&(跳|合|闸){1,}&(位置)", "断路器跳闸位置")
-	//new(test.UnitTest).TestDoiNameRex("[断|路|器]", "保护A相电流Ia1(正)")
+	//new(test.UnitTest).TestDoiNameRex("(测量|计量)&(电流.*C)|(C.*电流)|(IC1)", "测量电流C相")
 	go mqtt.Start()
 	if runmode == "dev" {
 		//自动生成接口权限定义

+ 39 - 4
service/models/bo/check_sysmodel_ied_fcda_relation.go

@@ -151,16 +151,51 @@ func (c *SysCheckModelFcdaRalationMgr) GetModelAllFcdaRef() (map[string][]orm.Pa
 			fc = v
 		}
 		key := fmt.Sprintf("%s,%s", tc, fc)
-		extref_name_exp := strings.ReplaceAll(tools.IsEmpty(row["to_fcda_match_exp"]), "/", "|")
+		extref_name_exp := tools.IsEmpty(row["to_fcda_match_exp"])
 		if extref_name_exp == "" {
 			extref_name_exp = tools.IsEmpty(row["to_fcda_name"])
 		}
-		row["to_fcda_match_exp"] = extref_name_exp
-		fcda_name_exp := strings.ReplaceAll(tools.IsEmpty(row["from_fcda_match_exp"]), "/", "|")
+		fcda_name_exp := tools.IsEmpty(row["from_fcda_match_exp"])
 		if fcda_name_exp == "" {
 			fcda_name_exp = tools.IsEmpty(row["from_fcda_name"])
 		}
-		row["from_fcda_match_exp"] = fcda_name_exp
+		t1 := []string{extref_name_exp, fcda_name_exp}
+		//中文字符替换
+		for i, exp := range t1 {
+			if strings.Index(exp, "/") > -1 {
+				exp = strings.ReplaceAll(exp, "/", "|")
+			}
+			if strings.Index(exp, "-") > -1 {
+				exp = strings.ReplaceAll(exp, "-", "\\-")
+			}
+			if strings.Index(exp, "|") > -1 {
+				exp = strings.ReplaceAll(exp, "|", "|")
+			}
+			if strings.Index(exp, ",") > -1 {
+				exp = strings.ReplaceAll(exp, ",", ",")
+			}
+			if strings.Index(exp, "(") > -1 {
+				exp = strings.ReplaceAll(exp, "(", "(")
+			}
+			if strings.Index(exp, ")") > -1 {
+				exp = strings.ReplaceAll(exp, ")", ")")
+			}
+			if strings.Index(exp, "【") > -1 {
+				exp = strings.ReplaceAll(exp, "【", "[")
+			}
+			if strings.Index(exp, "】") > -1 {
+				exp = strings.ReplaceAll(exp, "】", "]")
+			}
+			if strings.Index(exp, "{") > -1 {
+				exp = strings.ReplaceAll(exp, "{", "{")
+			}
+			if strings.Index(exp, "}") > -1 {
+				exp = strings.ReplaceAll(exp, "}", "}")
+			}
+			t1[i] = exp
+		}
+		row["to_fcda_match_exp"] = t1[0]
+		row["from_fcda_match_exp"] = t1[1]
 		if result[key] == nil {
 			result[key] = []orm.Params{}
 		}

+ 13 - 9
service/models/bo/check_sysmodel_ied_func_fcda.go

@@ -131,13 +131,16 @@ func (c *SysCheckModelIedFuncFcdaMgr) AutoRelation(modelid int, relationrow []T_
 	}
 	fcdaMap := map[string]T_data_model_func_def{}
 	for _, row := range relationrow {
-		key := fmt.Sprintf("%s%s", row.IedType, row.FcdaName)
-		if strings.Index(row.FuncName, "额定延") > -1 {
-			if strings.Index(row.FcdaName, "额定") > -1 && (strings.Index(row.FcdaName, "延迟") > -1 || strings.Index(row.FcdaName, "延时") > -1) {
-				key = fmt.Sprintf("%s%s", row.IedType, "额定延时")
+		receiveIedType := strings.Split(row.ReceiveIedType, ",")
+		for _, rit := range receiveIedType {
+			key := fmt.Sprintf("%s%s%s", row.IedType, strings.ReplaceAll(row.FcdaName, "*", ""), rit)
+			if strings.Index(row.FuncName, "额定延") > -1 {
+				if strings.Index(row.FcdaName, "额定") > -1 && (strings.Index(row.FcdaName, "延迟") > -1 || strings.Index(row.FcdaName, "延时") > -1) {
+					key = fmt.Sprintf("%s%s%s", row.IedType, "额定延时", rit)
+				}
 			}
+			fcdaMap[key] = row
 		}
-		fcdaMap[key] = row
 	}
 	//获取装置分组信息
 	bgm := new(SysCheckModelIedtypeGroupMgr)
@@ -158,10 +161,10 @@ func (c *SysCheckModelIedFuncFcdaMgr) AutoRelation(modelid int, relationrow []T_
 		if row.ReceiveIedType != "" && strings.Index(row.Inorout, "输出") > -1 {
 			tmplst := strings.Split(row.ReceiveIedType, ",")
 			for _, item := range tmplst {
-				key := fmt.Sprintf("%s%s", item, row.FcdaName)
+				key := fmt.Sprintf("%s%s%s", item, strings.ReplaceAll(row.FcdaName, "*", ""), row.IedType)
 				if strings.Index(row.FuncName, "额定延") > -1 {
 					if strings.Index(row.FcdaName, "额定") > -1 && (strings.Index(row.FcdaName, "延迟") > -1 || strings.Index(row.FcdaName, "延时") > -1) {
-						key = fmt.Sprintf("%s%s", item, "额定延时")
+						key = fmt.Sprintf("%s%s%s", item, "额定延时", row.IedType)
 					}
 				}
 				if r, h := fcdaMap[key]; h {
@@ -178,7 +181,7 @@ func (c *SysCheckModelIedFuncFcdaMgr) AutoRelation(modelid int, relationrow []T_
 					fr.Save()
 				} else {
 					//未完全匹配到端子时,查找其接收端的对侧装置为当前装置的端子
-					k := getRealIedCode(row.IedType, groupList) + "," + getRealIedCode(item, groupList)
+					k := getRealIedCode(row.IedType, groupList) + "," + getRealIedCode(item, groupList) + "," + row.FuncName
 					if _, h := noMatchList[k]; !h {
 						tmp := map[string]interface{}{"no": i, "fromrow": row}
 						noMatchList[k] = []interface{}{tmp}
@@ -192,12 +195,13 @@ func (c *SysCheckModelIedFuncFcdaMgr) AutoRelation(modelid int, relationrow []T_
 	//未完全匹配到端子时,查找其接收端的对侧装置为当前装置的端子
 	for iedtype, obj := range noMatchList {
 		ks := strings.Split(iedtype, ",")
+		//logger.Logger.Debug(fmt.Sprintf("装置类型%s,未匹配的端子列表:\n%+v", iedtype, obj))
 		subNo := 0 //相差的行数
 		fromrow := T_data_model_func_def{}
 		for i, row := range relationrow {
 			outIedType := getRealIedCode(row.IedType, groupList)
 			receiveIedType := getRealIedCode(row.ReceiveIedType, groupList)
-			if outIedType == ks[1] && strings.Index(receiveIedType, ks[0]) > -1 {
+			if outIedType == ks[1] && strings.Index(receiveIedType, ks[0]) > -1 && row.FuncName == ks[2] {
 				tmp := obj[0].(map[string]interface{})
 				no, _ := tmp["no"].(int)
 				subNo = no - i //相差的行数

+ 425 - 146
service/models/bo/checktools_area.go

@@ -242,7 +242,7 @@ func (c *CheckAreaMgr) GetIedList(scdid int64, areaid int) ([]orm.Params, error)
 			rowset[i]["attr_manufacturer"] = iedObj.Manufacturer
 			rowset[i]["ied_id"] = iedObj.NodeId
 		}
-		new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
+		//new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
 	}
 	return rowset, nil
 }
@@ -251,13 +251,27 @@ func (c *CheckAreaMgr) GetIedList(scdid int64, areaid int) ([]orm.Params, error)
 func (c *CheckAreaMgr) UpdateIeds(scdid int64, areaid int, ieds string) error {
 	db := orm.NewOrm()
 	iedlist := strings.Split(ieds, ",")
+	oldInfo := []orm.Params{}
+	iedNoMap := map[string]orm.Params{}
+	db.Raw("select * from t_data_check_area_ied where scd_id=? and area_id=?", scdid, areaid).Values(&oldInfo)
+	for _, row := range oldInfo {
+		iedNoMap[tools.IsEmpty(row["ied_name"])] = row
+	}
 	_, err := db.Raw("delete from t_data_check_area_ied where scd_id=? and area_id=?", scdid, areaid).Exec()
 	if err != nil {
 		logger.Logger.Error(err)
 		return err
 	}
 	for _, row := range iedlist {
-		_, err = db.Raw("insert into t_data_check_area_ied(scd_id,area_id,ied_name)values(?,?,?)", scdid, areaid, row).Exec()
+		iedno := tools.IsEmpty(iedNoMap[row]["ied_no"])
+		iedType := tools.IsEmpty(iedNoMap[row]["ied_type"])
+		pType := tools.IsEmpty(iedNoMap[row]["p_type"])
+		if iedType == "" {
+			iednameParts := new(ScdParse).ParseIedName(row)
+			iedType = iednameParts[0]
+			pType = iednameParts[1] + iednameParts[2]
+		}
+		_, err = db.Raw("insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_no,ied_type,p_type)values(?,?,?,?,?,?)", scdid, areaid, row, iedno, iedType, pType).Exec()
 		if err != nil {
 			logger.Logger.Error(err)
 			break
@@ -315,6 +329,203 @@ func (c *CheckAreaMgr) Reset() error {
 	return nil
 }
 
+//生成SCD装置虚端子表
+//scdid:SCD文件ID
+//areaids:指定的间隔列表。可以不指定,不指定时则生成全站所有装置的端子关系表
+//iedname:指定的装置名称。可以不指定。
+func (c *CheckAreaMgr) MakeExtrefReport(scdid int64, areaids []string, iedname string) (re []orm.Params, err error) {
+	findIeds := []orm.Params{}
+	scdParseMgr := new(ScdParse)
+	scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
+	if areaids != nil && len(areaids) > 0 {
+		for _, areaid := range areaids {
+			if areaid == "" {
+				continue
+			}
+			tmpid, _ := strconv.Atoi(areaid)
+			r, _ := c.GetIedList(scdid, tmpid)
+			if r == nil {
+				continue
+			}
+			findIeds = append(findIeds, r...)
+		}
+	} else if iedname != "" {
+		scdParseMgr := new(ScdParse)
+		scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
+		scdNode := new(ScdNode)
+		iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname)
+		if iedObj == nil {
+			return findIeds, errors.New("无效的装置名称:" + iedname)
+		}
+		rowset := orm.Params{"ied_name": iedname}
+		rowset["attr_name"] = iedObj.Name
+		rowset["attr_desc"] = iedObj.Desc
+		rowset["attr_config_version"] = iedObj.ConfigVersion
+		rowset["attr_type"] = iedObj.Type
+		rowset["attr_manufacturer"] = iedObj.Manufacturer
+		rowset["ied_id"] = iedObj.NodeId
+		findIeds = append(findIeds, rowset)
+	} else {
+		//获取所有的装置
+		for _, iedObj := range scdXmlObj.IED {
+			rowset := orm.Params{"ied_name": iedObj.Name}
+			rowset["attr_name"] = iedObj.Name
+			rowset["attr_desc"] = iedObj.Desc
+			rowset["attr_config_version"] = iedObj.ConfigVersion
+			rowset["attr_type"] = iedObj.Type
+			rowset["attr_manufacturer"] = iedObj.Manufacturer
+			rowset["ied_id"] = iedObj.NodeId
+			findIeds = append(findIeds, rowset)
+		}
+	}
+	scdNodeRule := new(ScdNodeRule)
+	scdNodeRule.SetScdXmlObject(scdXmlObj)
+	scdNode := new(ScdNode)
+	//获取端子的外部端子输入信号类型
+	var getFcdaType = func(inIedObj *node_attr.NIED, t2 *node_attr.NExtRef) string {
+		isFoundType := false
+		gooseorsv := ""
+		for _, ap := range inIedObj.AccessPoint {
+			if ap.Server == nil {
+				continue
+			}
+			for _, ld := range ap.Server.LDevice {
+				if ld.LN0 == nil {
+					continue
+				}
+				dsname := ""
+				for _, ds := range ld.LN0.DataSet {
+					for _, fcda := range ds.FCDA {
+						if fcda.LdInst == t2.LdInst && fcda.LnClass == t2.LnClass && fcda.LnInst == t2.LnInst && fcda.Prefix == t2.Prefix && fcda.DoName == t2.DoName {
+							if t2.DaName == "" || fcda.DaName == t2.DaName {
+								dsname = ds.Name
+								break
+							}
+						}
+					}
+					if dsname != "" {
+						break
+					}
+				}
+				//logger.Logger.Debug(fmt.Sprintf("%s装置FCDA(%+v)的数据集名称:%s", inIedObj.Name, t2, dsname))
+				if dsname != "" {
+					for _, smcrl := range ld.LN0.SampledValueControl {
+						if smcrl.DatSet == dsname {
+							gooseorsv = "SV"
+							break
+						}
+					}
+					if gooseorsv == "" {
+						for _, goosecrl := range ld.LN0.GSEControl {
+							if goosecrl.DatSet == dsname {
+								gooseorsv = "GOOSE"
+								break
+							}
+						}
+					}
+					isFoundType = true
+					break
+				}
+			}
+			if isFoundType {
+				break
+			}
+		}
+		return gooseorsv
+	}
+	//处理ied的端子关系
+	result := []orm.Params{}
+	for _, ied := range findIeds {
+		iedname := tools.IsEmpty(ied["ied_name"])
+		//获取extref
+		iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname)
+		if iedObj == nil {
+			logger.Logger.Error(errors.New("装置"+iedname+"未找到"), fmt.Sprintf("装置数据:%+v", ied))
+			continue
+		}
+		for _, t1 := range iedObj.AccessPoint {
+			if t1.Server == nil || len(t1.Server.LDevice) == 0 {
+				continue
+			}
+			for _, ld := range t1.Server.LDevice {
+				if ld.LN0 != nil && ld.LN0.Inputs != nil {
+					for _, t2 := range ld.LN0.Inputs.ExtRef {
+						doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
+						if doi == nil {
+							logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iedname, t2.IntAddr))
+							continue
+						}
+						itemRow := orm.Params{}
+						for k, v := range ied {
+							itemRow[k] = v
+						}
+						itemRow["doi_desc"] = doi.(*node_attr.NDOI).Desc
+						itemRow["doi_addr"] = t2.IntAddr
+						//获取外部ied信息
+						iniedname := t2.IedName
+						inIedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iniedname)
+						indoi, _ := scdNodeRule.IedFcdaExist(t2.IedName, t2.LdInst, t2.LnClass, t2.LnInst, t2.Prefix, t2.DoName, "")
+						if inIedObj == nil || indoi == nil {
+							logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iniedname, t2))
+							continue
+						} else {
+							//查找fcda的数据集及类型
+							itemRow["gooseorsv"] = getFcdaType(inIedObj, t2)
+							itemRow["in_ied_name"] = iniedname
+							itemRow["in_ied_desc"] = inIedObj.Desc
+							itemRow["in_doi_desc"] = indoi.(*node_attr.NDOI).Desc
+							daname := ""
+							if t2.DaName != "" {
+								daname = "." + t2.DaName
+							}
+							itemRow["in_doi_addr"] = fmt.Sprintf("%s/%s%s%s.%s%s", t2.LdInst, t2.Prefix, t2.LnClass, t2.LnInst, t2.DoName, daname)
+							result = append(result, itemRow)
+						}
+					}
+				}
+				for _, ln := range ld.LN {
+					if ln.Inputs == nil {
+						continue
+					}
+					for _, t2 := range ln.Inputs.ExtRef {
+						doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
+						if doi == nil {
+							logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iedname, t2.IntAddr))
+							continue
+						}
+						itemRow := orm.Params{}
+						for k, v := range ied {
+							itemRow[k] = v
+						}
+						itemRow["doi_desc"] = doi.(*node_attr.NDOI).Desc
+						itemRow["doi_addr"] = t2.IntAddr
+						//获取外部ied信息
+						iniedname := t2.IedName
+						inIedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iniedname)
+						indoi, _ := scdNodeRule.IedFcdaExist(t2.IedName, t2.LdInst, t2.LnClass, t2.LnInst, t2.Prefix, t2.DoName, "")
+						if inIedObj == nil || indoi == nil {
+							logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iniedname, t2))
+							continue
+						}
+						//查找fcda的数据集及类型
+						itemRow["gooseorsv"] = getFcdaType(inIedObj, t2)
+						itemRow["in_ied_name"] = iniedname
+						itemRow["in_ied_desc"] = inIedObj.Desc
+						itemRow["in_doi_desc"] = indoi.(*node_attr.NDOI).Desc
+						daname := ""
+						if t2.DaName != "" {
+							daname = "." + t2.DaName
+						}
+						itemRow["in_doi_addr"] = fmt.Sprintf("%s/%s%s%s.%s%s", t2.LdInst, t2.Prefix, t2.LnClass, t2.LnInst, t2.DoName, daname)
+						result = append(result, itemRow)
+					}
+				}
+			}
+		}
+	}
+	return result, nil
+}
+
 var areaCheckInfo = sync.Map{}
 
 //获取解析模型需要的基础数据信息
@@ -532,33 +743,35 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 		return fcdaObjList
 	}
 	//当前装置的所有信号发送端子列表
-	var getIedFcdas = func(iedname string) map[string]*node_attr.NFCDA {
-		iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
-		if iedObj == nil {
-			return nil
-		}
-		fcdaObjList := map[string]*node_attr.NFCDA{}
-		for _, t1 := range iedObj.AccessPoint {
-			if t1.Server == nil || len(t1.Server.LDevice) == 0 {
-				continue
+	/*
+		var getIedFcdas = func(iedname string) map[string]*node_attr.NFCDA {
+			iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
+			if iedObj == nil {
+				return nil
 			}
-			for _, ld := range t1.Server.LDevice {
-				if ld.LN0 != nil && len(ld.LN0.DataSet) > 0 {
-					for _, t2 := range ld.LN0.DataSet {
-						for _, t3 := range t2.FCDA {
-							re, _ := scdNodeRule.IedFcdaExist(iedname, t3.LdInst, t3.LnClass, t3.LnInst, t3.Prefix, t3.DoName, t3.DaName)
-							if re == nil {
-								continue
+			fcdaObjList := map[string]*node_attr.NFCDA{}
+			for _, t1 := range iedObj.AccessPoint {
+				if t1.Server == nil || len(t1.Server.LDevice) == 0 {
+					continue
+				}
+				for _, ld := range t1.Server.LDevice {
+					if ld.LN0 != nil && len(ld.LN0.DataSet) > 0 {
+						for _, t2 := range ld.LN0.DataSet {
+							for _, t3 := range t2.FCDA {
+								re, _ := scdNodeRule.IedFcdaExist(iedname, t3.LdInst, t3.LnClass, t3.LnInst, t3.Prefix, t3.DoName, t3.DaName)
+								if re == nil {
+									continue
+								}
+								doi := re.(*node_attr.NDOI)
+								fcdaObjList[doi.Desc] = t3
 							}
-							doi := re.(*node_attr.NDOI)
-							fcdaObjList[doi.Desc] = t3
 						}
 					}
 				}
 			}
+			return fcdaObjList
 		}
-		return fcdaObjList
-	}
+	*/
 	//从装置类型code中解析出类型代码和电压等级
 	var getIedTypeAndVolCode = func(ied_type string) (string, string) {
 		tmp := strings.Split(ied_type, "#")
@@ -614,7 +827,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 	//已经加载过遥信的装置
 	isLoadYxIed := map[string]map[*node_attr.NExtRef][]string{}
 	//已经处理过遥信端子的装置
-	isDealYxIed := map[string]int{}
+	//isDealYxIed := map[string]int{}
 	//已获取端子的装置
 	isLoadExtref := map[string]map[string]*node_attr.NExtRef{}
 	for _, row := range arealist {
@@ -725,7 +938,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 					if iedObj == nil && outIedObj == nil {
 						continue
 					}
-					outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
+					//outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
 					//是否设置的端子编号
 					noText := tools.IsEmpty(ied["ied_no"])
 					if noText == "" {
@@ -737,6 +950,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						fcda_name := tools.IsEmpty(r["from_fcda_name"])
 						extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
 						fcda_name_exp := tools.IsEmpty(r["from_fcda_match_exp"])
+						funcName := tools.IsEmpty(r["to_func_name"])
 						//端子编号处理
 						if strings.Index(extref_name_exp, "{no}") > -1 {
 							extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", noText)
@@ -744,21 +958,28 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						if strings.Index(fcda_name_exp, "{no}") > -1 {
 							fcda_name_exp = strings.ReplaceAll(fcda_name_exp, "{no}", noText)
 						}
+
 						funcExist := false //判断接收端设计的端子是否存在
 						extrefObj := new(node_attr.NExtRef)
 						fcda2Exist := false
-						fcdaObj := new(node_attr.NFCDA)
 						isYx := false
 						for desc, item := range extreflist {
-							//logger.Logger.Debug(fmt.Sprintf("接收装置%s的设计端子%s匹配SCD ExtRef DO端子%s", iedname, extref_name_exp, desc))
-							if tools.RexGroupTestMatch(extref_name_exp, desc) {
-								//判断是否是遥信端子
-								if yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", item.IedName, item.IntAddr, item.LdInst, item.Prefix, item.LnClass, item.LnInst, item.DoName)] == 1 {
+							if item.IedName != outiedname {
+								continue
+							}
+							//判断是否是遥信端子
+							/*
+								if strings.Index(funcName, "遥信") > -1 && yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", item.IedName, item.IntAddr, item.LdInst, item.Prefix, item.LnClass, item.LnInst, item.DoName)] == 1 {
 									isYx = true
 									break
 								}
+							*/
+							//logger.Logger.Debug(fmt.Sprintf("接收装置%s的设计端子%s匹配SCD ExtRef DO端子%s", iedname, extref_name_exp, desc))
+							macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, desc)
+							if macthResult {
 								funcExist = true
 								extrefObj = item
+								extref_name = desc //实际的端子名称
 								break
 							}
 						}
@@ -768,12 +989,72 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						}
 						if funcExist {
 							//判断输出端端子是否存在
-							for desc, item := range outiedFcdaList {
-								//logger.Logger.Debug(fmt.Sprintf("输出装置%s的设计端子%s匹配SCD FCDA DO端子%s", outiedname, fcda_name_exp, desc))
-								if tools.RexGroupTestMatch(fcda_name_exp, desc) {
-									fcda2Exist = true
-									fcdaObj = item
-									break
+							doi, _ := scdNodeRule.IedFcdaExist(extrefObj.IedName, extrefObj.LdInst, extrefObj.LnClass, extrefObj.LnInst, extrefObj.Prefix, extrefObj.DoName, "")
+							if doi != nil {
+								daname := ""
+								if extrefObj.DaName != "" {
+									daname = "." + extrefObj.DaName
+								}
+								fcda2Exist = true
+								fcda_name = doi.(*node_attr.NDOI).Desc //实际的端子名称
+								if strings.Index(funcName, "遥信") > -1 {
+									//2端端子名称需要完全相同
+									if extref_name != fcda_name {
+										parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s关联错误:端子名称不相同", area_name, iedname, extref_name, outiedname, fcda_name)
+										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":  outIedObjDesc,
+											"fcda_desc":     extref_name,
+											"fcda_addr":     extrefObj.IntAddr,
+											"out_fcda_desc": fcda_name,
+											"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
+											"error_type":    "2",
+										}
+										//检查未通过
+										scdNodeRule.AppendFcdaCheckResult(re)
+									} else {
+										//判断是否是双点或单点遥信端子
+										extrefDoi := scdNodeRule.IedIntAddrExist(iedname, extrefObj.IntAddr)
+										extrefDoiCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, extrefDoi.(*node_attr.NDOI))
+										fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, doi.(*node_attr.NDOI))
+										if extrefDoiCdcCode != fcdaCdcCode {
+											//错误:cdc类型不一致
+											parse_result := fmt.Sprintf("间隔%s的接收装置%s遥信端子%s与输出装置%s端子%s的CDC类型不一致(%s,%s)", area_name, iedname, extrefDoi.(*node_attr.NDOI).Desc, outiedname, doi.(*node_attr.NDOI).Desc, extrefDoiCdcCode, fcdaCdcCode)
+											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":  outIedObjDesc,
+												"fcda_desc":     extref_name,
+												"fcda_addr":     extrefObj.IntAddr,
+												"out_fcda_desc": fcda_name,
+												"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
+												"error_type":    "2",
+											}
+											//检查未通过
+											scdNodeRule.AppendFcdaCheckResult(re)
+										}
+									}
+									continue
+								}
+								macthResult, _ := tools.RexGroupTestMatch(fcda_name_exp, fcda_name)
+								if !macthResult {
+									parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误", area_name, iedname, extref_name, outiedname, fcda_name)
+									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":  outIedObjDesc,
+										"fcda_desc":     extref_name,
+										"fcda_addr":     extrefObj.IntAddr,
+										"out_fcda_desc": fcda_name,
+										"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
+										"error_type":    "2",
+									}
+									//检查未通过
+									scdNodeRule.AppendFcdaCheckResult(re)
 								}
 							}
 						}
@@ -792,43 +1073,28 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 							}
 							//检查未通过
 							scdNodeRule.AppendFcdaCheckResult(re)
-						} else {
-							//检查端子是否关联正确
+						} else if !fcda2Exist {
 							//fcda2Exist为false表示实际的端子from ied不是当前设计的ied
-							//fcda2Exist为true时,进一步判断端子地址是否与设计相符
-							if !fcda2Exist || (extrefObj.LdInst != fcdaObj.LdInst ||
-								extrefObj.LnInst != fcdaObj.LnInst ||
-								extrefObj.LnClass != fcdaObj.LnClass ||
-								extrefObj.Prefix != fcdaObj.Prefix ||
-								extrefObj.DoName != fcdaObj.DoName) {
-								//不正确
-								//logger.Logger.Debug(fmt.Sprintf("extref_name:%s extref_name_exp:%s extrefObj:%+v", extref_name, extref_name_exp, extrefObj))
-								//logger.Logger.Debug(fmt.Sprintf("fcda_name:%s fcda_name_exp:%s fcdaObj:%+v", fcda_name, fcda_name_exp, fcdaObj))
-								parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误", area_name, iedname, extref_name, outiedname, fcda_name)
-								daname := ""
-								if fcdaObj.DaName != "" {
-									daname = "." + fcdaObj.DaName
-								}
-								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":  outIedObjDesc,
-									"fcda_desc":     extref_name,
-									"fcda_addr":     extrefObj.IntAddr,
-									"out_fcda_desc": fcda_name,
-									"out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", fcdaObj.LdInst, fcdaObj.Prefix, fcdaObj.LnClass, fcdaObj.LnInst, fcdaObj.DoName, daname),
-									"error_type":    "2",
-								}
-								//检查未通过
-								scdNodeRule.AppendFcdaCheckResult(re)
+							parse_result := fmt.Sprintf("间隔%s下%s的输入装置%s缺失端子%s", area_name, iedname, outiedname, fcda_name)
+							re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
+								"ied_name":      iedname,
+								"ied_desc":      iedObjDesc,
+								"out_ied_name":  outiedname,
+								"out_ied_desc":  outIedObjDesc,
+								"fcda_desc":     extref_name,
+								"fcda_addr":     extrefObj.IntAddr,
+								"out_fcda_desc": fcda_name,
+								"out_fcda_addr": "",
+								"error_type":    "3",
 							}
+							//检查未通过
+							scdNodeRule.AppendFcdaCheckResult(re)
 						}
 					}
 					//检查是否有多余(SCD中有不存在于设计中)的端子
 					for extrefdesc, r := range extreflist { //scd中的端子关系
-						//判断是否是遥信端子
-						if yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", r.IedName, r.IntAddr, r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName)] == 1 {
+						//判断是否是当前输入装置和遥信端子
+						if r.IedName != outiedname || yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", r.IedName, r.IntAddr, r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName)] == 1 {
 							continue
 						}
 						extref_name := ""
@@ -836,7 +1102,12 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						isHave := false
 						for _, r1 := range refrow { //设计的端子关系
 							extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
-							if extrefdesc == extref_name_exp || tools.RexGroupTestMatch(extref_name_exp, extrefdesc) {
+							//端子编号处理
+							if strings.Index(extref_name_exp, "{no}") > -1 {
+								extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", noText)
+							}
+							macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, extrefdesc)
+							if extrefdesc == extref_name_exp || macthResult {
 								//端子存在
 								isHave = true
 								break
@@ -875,43 +1146,69 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 				}
 				//判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
 				//遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致以及单双点类型是否相同,以及是否有缺失和多余的遥信端子
-				if len(yx) > 0 && isDealYxIed[iedname] == 0 {
-					//logger.Logger.Debug(fmt.Sprintf("=============正在处理装置%s遥信端子数:%d  %+v", iedname, len(yx), isDealYxIed))
-					isDealYxIed[iedname] = 1
-					for extref, doiinfo := range yx {
-						doiDesc := doiinfo[0]
-						doiCdc := doiinfo[1]
-						daname := ""
-						if extref.DaName != "" {
-							daname = "." + extref.DaName
-						}
-						//获取输出端端子名称
-						outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
-						tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, extref.IedName)
-						if tmpIedObj == nil || 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":  tmpIedObj.Name,
-								"out_ied_desc":  tmpIedObj.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",
+				/*
+					if len(yx) > 0 && isDealYxIed[iedname] == 0 {
+						//logger.Logger.Debug(fmt.Sprintf("=============正在处理装置%s遥信端子数:%d  %+v", iedname, len(yx), isDealYxIed))
+						isDealYxIed[iedname] = 1
+						for extref, doiinfo := range yx {
+							doiDesc := doiinfo[0]
+							doiCdc := doiinfo[1]
+							daname := ""
+							if extref.DaName != "" {
+								daname = "." + extref.DaName
 							}
-							//检查未通过
-							scdNodeRule.AppendFcdaCheckResult(re)
-							continue
-						}
-						if doiCdc != "" && (!YaoXinDBType[doiCdc] || !YaoXinSiType[doiCdc]) {
-							//判断是否是双点或单点遥信端子
-							fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, outFcdaDoi.(*node_attr.NDOI))
-							if doiCdc != fcdaCdcCode {
-								//错误:cdc类型不一致
-								parse_result := fmt.Sprintf("间隔%s的接收装置%s遥信端子%s与输出装置%s端子%s的CDC类型不一致(%s,%s)", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc, doiCdc, fcdaCdcCode)
+							//获取输出端端子名称
+							outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
+							tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, extref.IedName)
+							if tmpIedObj == nil || outFcdaDoi == nil {
+								//端子缺失
+								tmpIedName := ""
+								tmpIedDesc := ""
+								if tmpIedObj != nil {
+									tmpIedName = tmpIedObj.Name
+									tmpIedDesc = tmpIedObj.Desc
+								}
+								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":  tmpIedName,
+									"out_ied_desc":  tmpIedDesc,
+									"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)
+								continue
+							}
+							if doiCdc != "" && (!YaoXinDBType[doiCdc] || !YaoXinSiType[doiCdc]) {
+								//判断是否是双点或单点遥信端子
+								fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, outFcdaDoi.(*node_attr.NDOI))
+								if doiCdc != fcdaCdcCode {
+									//错误:cdc类型不一致
+									parse_result := fmt.Sprintf("间隔%s的接收装置%s遥信端子%s与输出装置%s端子%s的CDC类型不一致(%s,%s)", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc, doiCdc, fcdaCdcCode)
+									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":  tmpIedObj.Name,
+										"out_ied_desc":  tmpIedObj.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)
+									continue
+								}
+							}
+							if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
+								//关联错误
+								parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, tmpIedObj.Name, 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,
@@ -925,35 +1222,16 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 								}
 								//检查未通过
 								scdNodeRule.AppendFcdaCheckResult(re)
-								continue
-							}
-						}
-						if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
-							//关联错误
-							parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, tmpIedObj.Name, 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":  tmpIedObj.Name,
-								"out_ied_desc":  tmpIedObj.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)
 						}
 					}
-				}
+				*/
 				yxAddrMap = nil
 				extreflist = nil
 			}
 		}
 	}
 	isLoadYxIed = nil
-	isDealYxIed = nil
 	scdNodeRule.CheckFinish()
 	scdNodeRule.Flush()
 	return nil
@@ -1219,6 +1497,7 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 				delMm = true
 				continue
 			}
+			ptype := strings.Split(tyCode, "#")[0]
 			//判断间隔是否需要包含差动装置
 			if strings.Contains(tyCode, "#C") {
 				_, iedname := getIedByDesc(ieds, tyCode, "差动")
@@ -1226,7 +1505,7 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 					for _, in := range iedname {
 						tmpIednameParts := scdParseMgr.ParseIedName(in)
 						if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
-							insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, tyCode[0:1], tyCode[1:]))
+							insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
 							break
 						}
 					}
@@ -1239,7 +1518,7 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 					for _, in := range iedname {
 						tmpIednameParts := scdParseMgr.ParseIedName(in)
 						if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
-							insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, tyCode[0:1], tyCode[1:]))
+							insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
 							break
 						}
 					}
@@ -1265,11 +1544,11 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 					//CT单独处理。它可能不分AB套
 					lastChar := tmpIednameParts[7]
 					if tmpIednameParts[6] == iednameParts[6] && (lastChar == "" || lastChar == iednameParts[7]) {
-						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					}
 				} else {
 					if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
-						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					}
 				}
 			}
@@ -1362,6 +1641,7 @@ func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm
 				//装置如果是分组成员装置,则不用检测
 				continue
 			}
+			ptype := strings.Split(tyCode, "#")[0]
 			if tyCode == pmCode {
 				//母线保护和母线合并单元装置编号跟随变压器
 				//查找变压器编号
@@ -1369,7 +1649,7 @@ func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm
 				inAreaIedName = c.getPMName(iednameParts, ieds)
 				pmIedName = inAreaIedName
 				if mmIedName == "" {
-					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
+					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:2]))
 					//pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
 					//使用PM装置的名称去定义MM的名称
 					tyCode = mmCode
@@ -1386,21 +1666,19 @@ func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm
 					continue
 				}
 			} else {
-				inAreaIedName = tyCode + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
+				inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
 			}
 			if strings.Index("ABCDE", iednameParts[7]) > -1 {
 				//最后一位是字母则说明是AB套
-				switch tyCode {
+				switch ptype {
 				case clCode:
 					if strings.Contains(iedtypes, "PLC") || strings.Contains(iedtypes, "PCL") {
 						//不处理CL装置
 					} else {
 						//测控装置,先判断是否分了AB套,没有标识(ied名称的最后一位是否是字母)则说明是多套共用装置
-						clIedname := inAreaIedName + iednameParts[7]
-						iedObj := ieds[inAreaIedName]
-						if iedObj != nil {
-							//当前测控装置也分了AB套
-							inAreaIedName = clIedname
+						if ieds[inAreaIedName] == nil {
+							//当前测控装置没有分AB套
+							inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
 						}
 					}
 					break
@@ -1408,7 +1686,7 @@ func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm
 					break
 				}
 			}
-			insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+			insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 		}
 		_, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
 		if err != nil {
@@ -1475,6 +1753,7 @@ func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm
 				iednameParts[7] = abCode
 			}
 			tyCode := c.getIedTypeCode(modelid, ty)
+			ptype := strings.Split(tyCode, "#")[0]
 			inAreaIedName := ""
 			if tyCode == pmCode {
 				//母线保护和母线合并单元装置编号跟随变压器
@@ -1483,7 +1762,7 @@ func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm
 				inAreaIedName = c.getPMName(iednameParts, ieds)
 				pmIedName = inAreaIedName
 				if mmIedName == "" {
-					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:2]))
+					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
 					//使用PM装置的名称去定义MM的名称
 					tyCode = "MM"
@@ -1500,15 +1779,14 @@ func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm
 					continue
 				}
 			} else {
-				tyCode = tyCode[0:1] + pjIed[1:2]
-				inAreaIedName = tyCode + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
+				inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
 				//判断与基准保护装置相同套号的装置是否存在
 				if ieds[inAreaIedName] == nil {
 					//尝试去除套号
-					inAreaIedName = tyCode + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
+					inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
 				}
 			}
-			insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:2]))
+			insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 		}
 		_, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
 		if err != nil {
@@ -1605,33 +1883,34 @@ func (c *CheckAreaMgr) pM(modelid int, vol, iedtypes string, ieds map[string]orm
 				//装置如果是分组成员装置,则不用检测
 				continue
 			}
+			ptype := strings.Split(tyCode, "#")[0]
 			if tyCode == mmCode {
 				//MM:母线合并单元
 				inAreaIedName = c.getMMName(iednameParts, ieds, abCode)
 				if inAreaIedName != "" {
-					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+					insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 				}
 			} else {
 				//需要查找同电压等级的所有同类同套装置
 				h, m, l := c.getIedListByVol(tyCode, ieds, volMap, abCode)
-				logger.Logger.Debug(fmt.Sprintf("当前PM装置:%s 电压等级:%s 提取类型:%s 套别:%s h:%+v,m:%+v,l:%+v", pl_iedname, pmVol, tyCode, abCode, h, m, l))
+				//logger.Logger.Debug(fmt.Sprintf("当前PM装置:%s 电压等级:%s 提取类型:%s 套别:%s h:%+v,m:%+v,l:%+v", pl_iedname, pmVol, ptype, abCode, h, m, l))
 				switch pmVol {
 				case "hight":
 					for _, item := range h {
 						inAreaIedName = tools.IsEmpty(item["ied_name"])
-						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					}
 					break
 				case "middle":
 					for _, item := range m {
 						inAreaIedName = tools.IsEmpty(item["ied_name"])
-						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					}
 					break
 				case "low":
 					for _, item := range l {
 						inAreaIedName = tools.IsEmpty(item["ied_name"])
-						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, tyCode[0:1], tyCode[1:]))
+						insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
 					}
 					break
 				}

+ 37 - 36
service/models/bo/scd_mgr.go

@@ -1226,35 +1226,35 @@ func (c *ScdMgr) CrcCheck(scdid string) (bool, error) {
 }
 
 var YaoCeMap = map[string]string{
-	"MV":   "MV",
-	"CMV":  "CMV",
-	"SAV":  "SAV",
-	"WYE":  "WYE",
-	"DEL":  "DEL",
-	"SEQ":  "SEQ",
-	"INC":  "INC",
-	"BSC":  "BSC",
-	"ISC":  "ISC",
-	"APC":  "APC",
-	"ENC":  "ENC",
-	"HMV":  "HMV",
-	"HWYE": "HWYE",
-	"HDEL": "HDEL",
-	"BAC":  "BAC",
+	"MV":   "测量值",
+	"CMV":  "复数测量值",
+	"SAV":  "呆样值",
+	"WYE":  "三相项系统中相对地相关测量值",
+	"DEL":  "三相项系统中相对相相关测量值",
+	"SEQ":  "顺序值",
+	"INC":  "可控整数状态",
+	"BSC":  "二进制受控步位置信息",
+	"ISC":  "整数受控步位置信息",
+	"APC":  "可控模拟过程信息",
+	"ENC":  "可控枚举状态",
+	"HMV":  "谐波值",
+	"HWYE": "WYE谐波值",
+	"HDEL": "DEL谐波值",
+	"BAC":  "可控的二进制模拟过程值",
 	"ING":  "整数状态定值",
 }
 var YaoXinMap = map[string]string{
-	"SPS": "SPS",
-	"DPS": "DPS",
-	"ACT": "ACT",
-	"ACD": "ACD",
-	"SPC": "SPC",
-	"DPC": "DPC",
-	"ENS": "ENS",
-	"VSS": "VSS",
+	"SPS": "单点状态信息",
+	"DPS": "双点状态信息",
+	"ACT": "保护激活信息",
+	"ACD": "方向保护激活信息",
+	"SPC": "可控的单点",
+	"DPC": "可控的双点",
+	"ENS": "枚举状态",
+	"VSS": "可见字符串状态",
 	"HST": "直方图",
-	"LPL": "LPL",
-	"DPL": "DPL",
+	"LPL": "逻辑节点铭牌",
+	"DPL": "设备铭牌",
 	"SEC": "安全违例计数",
 }
 
@@ -1270,14 +1270,14 @@ var YaoXinSiType = map[string]bool{
 	"SPC": true,
 }
 var YaoKongMap = map[string]string{
-	"SPC": "SPC",
-	"DPC": "DPC",
-	"INC": "INC",
-	"BSC": "BSC",
-	"ISC": "ISC",
-	"APC": "APC",
-	"ENC": "ENC",
-	"BAC": "BAC",
+	"SPC": "可控的单点",
+	"DPC": "可控的双点",
+	"INC": "可控的整数状态",
+	"BSC": "二进制受控步位置信息",
+	"ISC": "整数受控步位置信息",
+	"APC": "可控模拟过程信息",
+	"ENC": "可控枚举状态",
+	"BAC": "可控的二进制模拟过程值",
 }
 
 var DingZhiMap = map[string]string{
@@ -1287,15 +1287,16 @@ var DingZhiMap = map[string]string{
 	"STG":   "STG",
 	"ENG":   "枚举状态定值",
 	"ORG":   "对象引用定值",
-	"TSG":   "时间定值",
+	"TSG":   "时间定值",
 	"CSG":   "曲线形状定值",
 	"CUG":   "可见字符串定值",
 	"VSG":   "VSG",
 	"CURVE": "定值曲线",
 }
 var OtherCdcTypeMap = map[string]string{
-	"INS": "INS",
-	"BCR": "BCR",
+	"INS": "整数状态",
+	"BCR": "二进制计数器读数",
+	"CSD": "曲线形状描述",
 }
 
 //根据cdc返回对应的数据类型名称

+ 27 - 0
service/routers/commentsRouter_____________ME_GoProject_src_scd_check_tools_controllers.go

@@ -342,6 +342,15 @@ func init() {
 
     beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"],
         beego.ControllerComments{
+            Method: "RegTest",
+            Router: "/reg/test",
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"],
+        beego.ControllerComments{
             Method: "ResetUserPwd",
             Router: "/resetUserPwd",
             AllowHTTPMethods: []string{"post"},
@@ -684,6 +693,15 @@ func init() {
 
     beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"],
         beego.ControllerComments{
+            Method: "GetScdIedFcdaList",
+            Router: "/admin/scd/fcda/list",
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"],
+        beego.ControllerComments{
             Method: "DeleteSysModelByID",
             Router: "/admin/sysmodel/delete",
             AllowHTTPMethods: []string{"post"},
@@ -745,6 +763,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"],
+        beego.ControllerComments{
+            Method: "SaveCheckAreaIedNoByAreaID",
+            Router: "/admin/update/check_area/iedno",
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["scd_check_tools/controllers:ExcelController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ExcelController"],
         beego.ControllerComments{
             Method: "ExpTableData",

+ 18 - 0
service/routers/commentsRouter_controllers.go

@@ -342,6 +342,15 @@ func init() {
 
     beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"],
         beego.ControllerComments{
+            Method: "RegTest",
+            Router: "/reg/test",
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ApiController"],
+        beego.ControllerComments{
             Method: "ResetUserPwd",
             Router: "/resetUserPwd",
             AllowHTTPMethods: []string{"post"},
@@ -684,6 +693,15 @@ func init() {
 
     beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"],
         beego.ControllerComments{
+            Method: "GetScdIedFcdaList",
+            Router: "/admin/scd/fcda/list",
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:BusAdminController"],
+        beego.ControllerComments{
             Method: "DeleteSysModelByID",
             Router: "/admin/sysmodel/delete",
             AllowHTTPMethods: []string{"post"},

+ 75 - 0
service/static/swagger/swagger.json

@@ -813,6 +813,48 @@
                 }
             }
         },
+        "/admin/scd/fcda/list": {
+            "get": {
+                "tags": [
+                    "scd_check_tools/controllersBusAdminController"
+                ],
+                "summary": "获取SCD中装置实际配置的虚端子关系",
+                "description": "获取SCD中装置实际配置的虚端子关系",
+                "parameters": [
+                    {
+                        "in": "formData",
+                        "name": "scd_id",
+                        "description": "SCD文件ID",
+                        "required": true,
+                        "type": "integer",
+                        "format": "int64"
+                    },
+                    {
+                        "in": "formData",
+                        "name": "area_ids",
+                        "description": "指定的间隔列表,多个间隔使用逗号分隔。可以不指定,不指定时则生成全站所有装置的端子关系表",
+                        "type": "string"
+                    },
+                    {
+                        "in": "formData",
+                        "name": "ied_name",
+                        "description": "指定的装置名称。可以不指定。",
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "成功",
+                        "schema": {
+                            "$ref": "#/definitions/ResultOK"
+                        }
+                    },
+                    "500": {
+                        "description": "{object} ResultError  失败"
+                    }
+                }
+            }
+        },
         "/admin/sysmodel/delete": {
             "post": {
                 "tags": [
@@ -3698,6 +3740,39 @@
                 }
             }
         },
+        "/reg/test": {
+            "get": {
+                "tags": [
+                    "scd_check_tools/controllersApiController"
+                ],
+                "summary": "正则表达式匹配验证",
+                "description": "正则表达式匹配验证",
+                "parameters": [
+                    {
+                        "in": "query",
+                        "name": "regstr",
+                        "description": "正则表达式",
+                        "required": true,
+                        "type": "string"
+                    },
+                    {
+                        "in": "query",
+                        "name": "str",
+                        "description": "用于匹配的目标字符串",
+                        "required": true,
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "status   成功"
+                    },
+                    "500": {
+                        "description": "status  失败"
+                    }
+                }
+            }
+        },
         "/report/delete": {
             "post": {
                 "tags": [

+ 50 - 0
service/static/swagger/swagger.yml

@@ -558,6 +558,34 @@ paths:
             $ref: '#/definitions/ResultOK'
         "500":
           description: '{object} ResultError  失败'
+  /admin/scd/fcda/list:
+    get:
+      tags:
+      - scd_check_tools/controllersBusAdminController
+      summary: 获取SCD中装置实际配置的虚端子关系
+      description: 获取SCD中装置实际配置的虚端子关系
+      parameters:
+      - in: formData
+        name: scd_id
+        description: SCD文件ID
+        required: true
+        type: integer
+        format: int64
+      - in: formData
+        name: area_ids
+        description: 指定的间隔列表,多个间隔使用逗号分隔。可以不指定,不指定时则生成全站所有装置的端子关系表
+        type: string
+      - in: formData
+        name: ied_name
+        description: 指定的装置名称。可以不指定。
+        type: string
+      responses:
+        "200":
+          description: 成功
+          schema:
+            $ref: '#/definitions/ResultOK'
+        "500":
+          description: '{object} ResultError  失败'
   /admin/sysmodel/delete:
     post:
       tags:
@@ -2500,6 +2528,28 @@ paths:
             $ref: '#/definitions/WarpOK'
         "500":
           description: '{object} WarpError  失败'
+  /reg/test:
+    get:
+      tags:
+      - scd_check_tools/controllersApiController
+      summary: 正则表达式匹配验证
+      description: 正则表达式匹配验证
+      parameters:
+      - in: query
+        name: regstr
+        description: 正则表达式
+        required: true
+        type: string
+      - in: query
+        name: str
+        description: 用于匹配的目标字符串
+        required: true
+        type: string
+      responses:
+        "200":
+          description: status   成功
+        "500":
+          description: status  失败
   /report/delete:
     post:
       tags:

+ 75 - 0
service/swagger/swagger.json

@@ -813,6 +813,48 @@
                 }
             }
         },
+        "/admin/scd/fcda/list": {
+            "get": {
+                "tags": [
+                    "scd_check_tools/controllersBusAdminController"
+                ],
+                "summary": "获取SCD中装置实际配置的虚端子关系",
+                "description": "获取SCD中装置实际配置的虚端子关系",
+                "parameters": [
+                    {
+                        "in": "formData",
+                        "name": "scd_id",
+                        "description": "SCD文件ID",
+                        "required": true,
+                        "type": "integer",
+                        "format": "int64"
+                    },
+                    {
+                        "in": "formData",
+                        "name": "area_ids",
+                        "description": "指定的间隔列表,多个间隔使用逗号分隔。可以不指定,不指定时则生成全站所有装置的端子关系表",
+                        "type": "string"
+                    },
+                    {
+                        "in": "formData",
+                        "name": "ied_name",
+                        "description": "指定的装置名称。可以不指定。",
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "成功",
+                        "schema": {
+                            "$ref": "#/definitions/ResultOK"
+                        }
+                    },
+                    "500": {
+                        "description": "{object} ResultError  失败"
+                    }
+                }
+            }
+        },
         "/admin/sysmodel/delete": {
             "post": {
                 "tags": [
@@ -3698,6 +3740,39 @@
                 }
             }
         },
+        "/reg/test": {
+            "get": {
+                "tags": [
+                    "scd_check_tools/controllersApiController"
+                ],
+                "summary": "正则表达式匹配验证",
+                "description": "正则表达式匹配验证",
+                "parameters": [
+                    {
+                        "in": "query",
+                        "name": "regstr",
+                        "description": "正则表达式",
+                        "required": true,
+                        "type": "string"
+                    },
+                    {
+                        "in": "query",
+                        "name": "str",
+                        "description": "用于匹配的目标字符串",
+                        "required": true,
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "status   成功"
+                    },
+                    "500": {
+                        "description": "status  失败"
+                    }
+                }
+            }
+        },
         "/report/delete": {
             "post": {
                 "tags": [

+ 50 - 0
service/swagger/swagger.yml

@@ -558,6 +558,34 @@ paths:
             $ref: '#/definitions/ResultOK'
         "500":
           description: '{object} ResultError  失败'
+  /admin/scd/fcda/list:
+    get:
+      tags:
+      - scd_check_tools/controllersBusAdminController
+      summary: 获取SCD中装置实际配置的虚端子关系
+      description: 获取SCD中装置实际配置的虚端子关系
+      parameters:
+      - in: formData
+        name: scd_id
+        description: SCD文件ID
+        required: true
+        type: integer
+        format: int64
+      - in: formData
+        name: area_ids
+        description: 指定的间隔列表,多个间隔使用逗号分隔。可以不指定,不指定时则生成全站所有装置的端子关系表
+        type: string
+      - in: formData
+        name: ied_name
+        description: 指定的装置名称。可以不指定。
+        type: string
+      responses:
+        "200":
+          description: 成功
+          schema:
+            $ref: '#/definitions/ResultOK'
+        "500":
+          description: '{object} ResultError  失败'
   /admin/sysmodel/delete:
     post:
       tags:
@@ -2500,6 +2528,28 @@ paths:
             $ref: '#/definitions/WarpOK'
         "500":
           description: '{object} WarpError  失败'
+  /reg/test:
+    get:
+      tags:
+      - scd_check_tools/controllersApiController
+      summary: 正则表达式匹配验证
+      description: 正则表达式匹配验证
+      parameters:
+      - in: query
+        name: regstr
+        description: 正则表达式
+        required: true
+        type: string
+      - in: query
+        name: str
+        description: 用于匹配的目标字符串
+        required: true
+        type: string
+      responses:
+        "200":
+          description: status   成功
+        "500":
+          description: status  失败
   /report/delete:
     post:
       tags:

+ 26 - 9
service/test/test.go

@@ -228,35 +228,52 @@ func (t *UnitTest) Test19() {
 	logger.Logger.Println(fmt.Sprintf("============测试结果报告生成:%+v", testResult))
 }
 
-func (t *UnitTest) TestDoiNameRex() {
-	return
+func (t *UnitTest) TestDoiNameRex(regstr, soruce string) {
+
 	defer func() {
 		os.Exit(0)
 	}()
-	regstr := ""
-	soruce := ""
 	regstrs := strings.Split(regstr, "&")
+	if len(regstrs) == 1 {
+		//未分组时,直接匹配
+		fcdarex, err2 := regexp.Compile(regstr)
+		if err2 != nil {
+			logger.Logger.Error(err2, regstr)
+			return
+		}
+		r := fcdarex.MatchString(soruce)
+		if !r {
+			logger.Logger.Debug(errors.New("表达式验证未通过:" + regstr + "   匹配目标:" + soruce))
+		}
+		fmt.Println(fmt.Sprintf("匹配结果%+v", r))
+		return
+	}
 	wg := sync.WaitGroup{}
 	wg.Add(len(regstrs))
-	wgResultFalse := map[string]bool{}
+	wgResultFalse := sync.Map{}
 	for _, item := range regstrs {
 		go func(item string) {
 			fcdarex, err2 := regexp.Compile(item)
+			r := true
 			if err2 != nil {
 				logger.Logger.Error(err2, item)
-				wgResultFalse["false"] = false
+				r = false
+				wgResultFalse.Store("false", r)
 			} else if !fcdarex.MatchString(soruce) {
-				wgResultFalse["false"] = false
+				r = false
+				wgResultFalse.Store("false", r)
 			}
+			fmt.Println(fmt.Sprintf("表达式%s匹配结果%+v", item, r))
 			wg.Done()
 		}(item)
 	}
 	wg.Wait()
+	fmt.Println(fmt.Sprintf("匹配结果%+v", wgResultFalse))
 	matchSuccess := true
-	if _, h := wgResultFalse["false"]; h {
+	if _, h := wgResultFalse.Load("false"); h {
 		matchSuccess = false
 	}
-	fmt.Println(fmt.Sprintf("%+v", matchSuccess))
+	fmt.Println(fmt.Sprintf("总的匹配结果:%+v", matchSuccess))
 }
 
 func (t *UnitTest) TestIntAddrParse() {

+ 24 - 10
service/tools/tool.go

@@ -107,41 +107,55 @@ func CheckErr(err error) {
 //多个表达式组时使用&分隔,每个分组表达式可使用()括起来,更加易读,且内部内容必须符合正则表过式规则
 //表达式样例1:(断路器)&(跳|合|闸){1,}&(位置)
 //表达式样例2:Ia1&A&保护
-func RexGroupTestMatch(regstr, soruce string) bool {
+func RexGroupTestMatch(regstr, soruce string) (bool, error) {
 	if regstr == "" || soruce == "" {
-		return false
+		return false, errors.New("参数无效")
 	}
 	regstrs := strings.Split(regstr, "&")
-	if len(regstrs) > 1 {
+	if len(regstrs) == 1 {
 		//未分组时,直接匹配
 		fcdarex, err2 := regexp.Compile(regstr)
 		if err2 != nil {
 			logger.Logger.Error(err2, regstr)
-			return false
+			return false, errors.New("无效的正则表达式")
 		}
-		return fcdarex.MatchString(soruce)
+		r := fcdarex.MatchString(soruce)
+		/*
+			if !r {
+				logger.Logger.Debug(errors.New("表达式验证未通过:" + regstr + "   匹配目标:" + soruce))
+			}
+		*/
+		return r, nil
 	}
 	wg := sync.WaitGroup{}
 	wg.Add(len(regstrs))
-	wgResultFalse := map[string]bool{}
+	wgResultFalse := sync.Map{}
 	for _, item := range regstrs {
 		go func(item string) {
 			fcdarex, err2 := regexp.Compile(item)
+			r := true
 			if err2 != nil {
 				logger.Logger.Error(err2, item)
-				wgResultFalse["false"] = false
+				r = false
+				wgResultFalse.Store("false", r)
 			} else if !fcdarex.MatchString(soruce) {
-				wgResultFalse["false"] = false
+				r = false
+				wgResultFalse.Store("false", r)
 			}
+			/*
+				if !r {
+					logger.Logger.Debug(errors.New("部分表达式验证未通过:" + item + "   匹配目标:" + soruce))
+				}
+			*/
 			wg.Done()
 		}(item)
 	}
 	wg.Wait()
 	matchSuccess := true
-	if _, h := wgResultFalse["false"]; h {
+	if _, h := wgResultFalse.Load("false"); h {
 		matchSuccess = false
 	}
-	return matchSuccess
+	return matchSuccess, nil
 }
 
 //生成全局唯一ID序列