|
@@ -3,6 +3,7 @@ package bo
|
|
|
import (
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
+ "regexp"
|
|
|
"scd_check_tools/logger"
|
|
|
"scd_check_tools/models/enum"
|
|
|
"scd_check_tools/models/node_attr"
|
|
@@ -308,15 +309,21 @@ func (c *CheckAreaMgr) Reset() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-//检测间隔装置关系正确性
|
|
|
-func (c *CheckAreaMgr) CheckAreaIedRelation() error {
|
|
|
- // 获取当前scd中需要检查的间隔
|
|
|
+var areaCheckInfo = sync.Map{}
|
|
|
+
|
|
|
+//获取解析模型需要的基础数据信息
|
|
|
+func (c *CheckAreaMgr) getAreaCheckInfo() (*node_attr.SCL, []orm.Params, string, error) {
|
|
|
+ key := fmt.Sprintf("%d-checkinfo", c.ScdId)
|
|
|
+ if v, h := areaCheckInfo.Load(key); h {
|
|
|
+ v1 := v.([]interface{})
|
|
|
+ return v1[0].(*node_attr.SCL), v1[1].([]orm.Params), v1[2].(string), nil
|
|
|
+ }
|
|
|
arealist := []orm.Params{}
|
|
|
db := orm.NewOrm()
|
|
|
_, err := db.Raw("select id,area_name,area_type,model_id from t_data_check_area where scd_id=?", c.ScdId).Values(&arealist)
|
|
|
if err != nil {
|
|
|
logger.Logger.Error(err)
|
|
|
- return err
|
|
|
+ return nil, nil, "", err
|
|
|
}
|
|
|
scdNodeRule := new(ScdNodeRule)
|
|
|
area_ruleid := ""
|
|
@@ -325,27 +332,47 @@ func (c *CheckAreaMgr) CheckAreaIedRelation() error {
|
|
|
area_ruleid = tools.IsEmpty(area_ruleList[0]["id"])
|
|
|
}
|
|
|
if area_ruleid == "" {
|
|
|
- return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
|
|
|
+ return nil, nil, "", errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
|
|
|
}
|
|
|
scdParseMgr := new(ScdParse)
|
|
|
scdXmlObj, serr := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
|
|
|
if serr != nil {
|
|
|
- return serr
|
|
|
+ return nil, nil, "", serr
|
|
|
+ }
|
|
|
+ if scdXmlObj == nil {
|
|
|
+ return nil, nil, "", errors.New("无效的SCD")
|
|
|
+ }
|
|
|
+ areaCheckInfo.Store(key, []interface{}{scdXmlObj, arealist, area_ruleid})
|
|
|
+ return scdXmlObj, arealist, area_ruleid, nil
|
|
|
+}
|
|
|
+
|
|
|
+//检测间隔装置关系正确性
|
|
|
+func (c *CheckAreaMgr) CheckAreaIedRelation() error {
|
|
|
+ // 获取当前scd中需要检查的间隔
|
|
|
+ scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
|
|
|
+ db := orm.NewOrm()
|
|
|
+ if err != nil {
|
|
|
+ logger.Logger.Error(err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if area_ruleid == "" {
|
|
|
+ return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
|
|
|
}
|
|
|
if scdXmlObj == nil {
|
|
|
return errors.New("无效的SCD")
|
|
|
}
|
|
|
+ scdNodeRule := new(ScdNodeRule)
|
|
|
scdNode := new(ScdNode)
|
|
|
model_refs := map[string][]orm.Params{} //模型定义的装置关系定义
|
|
|
area_ieds := map[string][]orm.Params{} //间隔下的装置列表
|
|
|
+ iedRelationMgr := new(SysCheckModelIedRelationMgr)
|
|
|
for _, row := range arealist {
|
|
|
//获取间隔标准装置及关系
|
|
|
- modelid := tools.IsEmpty(row["model_id"])
|
|
|
+ modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
|
|
|
//area_name := tools.IsEmpty(row["area_name"])
|
|
|
//area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
|
|
|
area_id := tools.IsEmpty(row["id"])
|
|
|
- s := []orm.Params{}
|
|
|
- _, err = db.Raw("select from_ied_code,to_ied_code,in_type from t_data_model_relation_def where model_id=?", modelid).Values(&s)
|
|
|
+ s, err := iedRelationMgr.GetListByModelid(modelid)
|
|
|
if err != nil {
|
|
|
logger.Logger.Error(err)
|
|
|
return err
|
|
@@ -353,7 +380,7 @@ func (c *CheckAreaMgr) CheckAreaIedRelation() error {
|
|
|
if len(s) == 0 {
|
|
|
return errors.New(fmt.Sprintf("模型%d还未配置装置关系", modelid))
|
|
|
}
|
|
|
- model_refs[modelid] = s
|
|
|
+ model_refs[fmt.Sprintf("%d", modelid)] = s
|
|
|
/*
|
|
|
hasIeds := map[string]bool{}
|
|
|
for _, row1 := range s {
|
|
@@ -441,9 +468,202 @@ func (c *CheckAreaMgr) CheckAreaIedRelation() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+//检测装置功能分析
|
|
|
+func (c *CheckAreaMgr) CheckIedFunc() error {
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+//检测装置端子分析
|
|
|
+func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
+ scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
|
|
|
+ if err != nil {
|
|
|
+ logger.Logger.Error(err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if area_ruleid == "" {
|
|
|
+ return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
|
|
|
+ }
|
|
|
+ if scdXmlObj == nil {
|
|
|
+ return errors.New("无效的SCD")
|
|
|
+ }
|
|
|
+ db := orm.NewOrm()
|
|
|
+ //获取当前站的各电压等级
|
|
|
+ volRows := []orm.Params{}
|
|
|
+ _, err = db.Raw("select t.vol, CAST(REPLACE(UPPER(g.name),'KV','') as SIGNED) volname from t_area_ied_relation t,global_const_code g where g.code=CONCAT('v_level_',t.vol) and g.parentcode='voltage_level' and t.vol!=999 and t.scd_id=? GROUP BY t.vol ORDER BY volname desc", c.ScdId).Values(&volRows)
|
|
|
+ if err != nil {
|
|
|
+ logger.Logger.Error(err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if len(volRows) == 0 {
|
|
|
+ logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
|
|
|
+ return errors.New("该scd未发现任何电压等级的装置")
|
|
|
+ }
|
|
|
+ volMap := map[string]string{}
|
|
|
+ volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
|
|
|
+ if len(volRows) == 2 {
|
|
|
+ volMap["middle"] = ""
|
|
|
+ volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
|
|
|
+ } else {
|
|
|
+ volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
|
|
|
+ volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
|
|
|
+ }
|
|
|
+ scdNodeRule := new(ScdNodeRule)
|
|
|
+ scdNodeMgr := new(ScdNode)
|
|
|
+ iedRelationMgr := new(SysCheckModelIedRelationMgr)
|
|
|
+ for _, row := range arealist {
|
|
|
+ //获取间隔标准装置及关系
|
|
|
+ modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
|
|
|
+ area_name := tools.IsEmpty(row["area_name"])
|
|
|
+ //area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
|
|
|
+ area_id := tools.IsEmpty(row["id"])
|
|
|
+ s, err := iedRelationMgr.GetListByModelid(modelid)
|
|
|
+ if err != nil {
|
|
|
+ logger.Logger.Error(err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if len(s) == 0 {
|
|
|
+ return errors.New(fmt.Sprintf("模型%d还未配置装置关系", modelid))
|
|
|
+ }
|
|
|
+ //获取该间隔下该类型的装置
|
|
|
+ s1 := []orm.Params{}
|
|
|
+ _, err = db.Raw("select ied_name from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
|
|
|
+ //循环处理关联关系
|
|
|
+ dealIedType := map[string]int{} //已处理过的装置类型
|
|
|
+ for _, row2 := range s {
|
|
|
+ ied_type := tools.IsEmpty(row2["ied_type"])
|
|
|
+ if dealIedType[ied_type] > 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ //获取装置类型配置的端子列表
|
|
|
+ fcdaMgr := new(SysCheckModelIedFuncFcdaMgr)
|
|
|
+ funcMgr := new(SysCheckModelIedFuncMgr)
|
|
|
+ funcMgr.Model = T_data_model_func_def{ModelId: modelid}
|
|
|
+ funclist, _ := funcMgr.GetList(modelid, ied_type)
|
|
|
+ if funclist == nil || len(funclist) == 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ tmp := strings.Split(ied_type, "#")
|
|
|
+ ied_type = tmp[0]
|
|
|
+ vol := ""
|
|
|
+ if len(tmp) == 2 {
|
|
|
+ vol = tmp[1] //电压级别
|
|
|
+ }
|
|
|
+ iedlst := []orm.Params{}
|
|
|
+ if vol == "" {
|
|
|
+ for _, r := range s1 {
|
|
|
+ if strings.HasPrefix(tools.IsEmpty(r["ied_name"]), ied_type) {
|
|
|
+ iedlst = append(iedlst, r)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ tmpLst := map[string]orm.Params{}
|
|
|
+ for _, r := range s1 {
|
|
|
+ iedname := tools.IsEmpty(r["ied_name"])
|
|
|
+ if strings.HasPrefix(iedname, ied_type) {
|
|
|
+ tmpLst[iedname] = r
|
|
|
+ }
|
|
|
+ }
|
|
|
+ h, m, l := c.getIedListByVol(ied_type, tmpLst, volMap)
|
|
|
+ if vol == "H" {
|
|
|
+ iedlst = h
|
|
|
+ }
|
|
|
+ if vol == "M" {
|
|
|
+ iedlst = m
|
|
|
+ }
|
|
|
+ if vol == "L" {
|
|
|
+ iedlst = l
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, ied := range iedlst {
|
|
|
+ iedname := tools.IsEmpty(ied["ied_name"])
|
|
|
+ iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
|
|
|
+ if iedObj == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ fcdaObjList := []*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 {
|
|
|
+ for _, t2 := range ld.LN0.DataSet {
|
|
|
+ for _, t3 := range t2.FCDA {
|
|
|
+ fcdaObjList = append(fcdaObjList, t3)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, row3 := range funclist {
|
|
|
+ funcExist := false //设计的功能是否存在
|
|
|
+ funcid, _ := strconv.Atoi(tools.IsEmpty(row3["id"]))
|
|
|
+ fcdaMgr.Model = T_data_model_func_fcda{ModelId: modelid, FuncId: funcid}
|
|
|
+ fcdalist, _ := fcdaMgr.GetList()
|
|
|
+ if fcdalist != nil && len(fcdalist) > 0 {
|
|
|
+ //判断端子是否存在
|
|
|
+ for _, row4 := range fcdalist {
|
|
|
+ fcda_name_match := tools.IsEmpty(row4["fcda_match_exp"])
|
|
|
+ fcda_name := tools.IsEmpty(row4["fcda_name"])
|
|
|
+ if fcda_name_match == "" {
|
|
|
+ fcda_name_match = fcda_name
|
|
|
+ }
|
|
|
+ fcdaExist := false
|
|
|
+ //获取端子FCDA描述
|
|
|
+ if len(fcdaObjList) > 0 {
|
|
|
+ for _, t4 := range fcdaObjList {
|
|
|
+ re, _ := scdNodeRule.IedFcdaExist(iedname, t4.LdInst, t4.LnClass, t4.LnInst, t4.Prefix, t4.DoName, t4.DaName)
|
|
|
+ if re == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ doi := re.(*node_attr.NDOI)
|
|
|
+ desc := doi.Desc
|
|
|
+ if fcda_name_match == desc {
|
|
|
+ //完全匹配
|
|
|
+ fcdaExist = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ //正则匹配
|
|
|
+ //fcda_name_match = strings.ReplaceAll(fcda_name_match)
|
|
|
+ rexp := regexp.MustCompile(fcda_name_match)
|
|
|
+ if rexp.FindString(desc) != "" {
|
|
|
+ fcdaExist = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if fcdaExist {
|
|
|
+ funcExist = true
|
|
|
+ } else {
|
|
|
+ parse_result := fmt.Sprintf("间隔%s的装置%s缺失虚端子%s", area_name, iedname, fcda_name)
|
|
|
+ r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
|
|
|
+ //检查未通过
|
|
|
+ scdNodeRule.AppendPaseResult(r)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !funcExist {
|
|
|
+ parse_result := fmt.Sprintf("间隔%s的装置%s缺失功能%s", area_name, iedname, tools.IsEmpty(row3["func_name"]))
|
|
|
+ r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
|
|
|
+ //检查未通过
|
|
|
+ scdNodeRule.AppendPaseResult(r)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dealIedType[ied_type] = 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ scdNodeRule.CheckFinish()
|
|
|
+ scdNodeRule.Flush()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
//解析模型间隔
|
|
|
func (c *CheckAreaMgr) ParseModelArea() {
|
|
|
c.Init(c.ScdId)
|
|
|
+ key := fmt.Sprintf("%d-checkinfo", c.ScdId)
|
|
|
+ areaCheckInfo.Delete(key)
|
|
|
// 取得当前scd所有ied及名称解析结果
|
|
|
dbo := orm.NewOrm()
|
|
|
sql := "select t.*,t1.name area_name from t_area_ied_relation t,t_substation_area t1 where t.area_id=t1.id and t.scd_id=? order by t.p_type"
|
|
@@ -1082,7 +1302,8 @@ func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
|
|
|
dealFromIed := map[string]int{}
|
|
|
for _, row := range ied_refs {
|
|
|
fromiedtype := tools.IsEmpty(row["from_ied_code"])
|
|
|
- toiedtype := tools.IsEmpty(row["to_ied_code"])
|
|
|
+ fromiedtype = strings.Split(fromiedtype, "#")[0] //去除后面的电压级别标识
|
|
|
+ toiedtype := strings.Split(tools.IsEmpty(row["to_ied_code"]), "#")[0] //去除后面的电压级别标识
|
|
|
reftype := tools.IsEmpty(row["in_type"])
|
|
|
tmpFromAreaIeds := []orm.Params{}
|
|
|
tmpToAreaIeds := []orm.Params{}
|