checktools_area.go 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587
  1. package bo
  2. import (
  3. "errors"
  4. "fmt"
  5. "regexp"
  6. "scd_check_tools/logger"
  7. "scd_check_tools/models/enum"
  8. "scd_check_tools/models/node_attr"
  9. "scd_check_tools/tools"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. "github.com/astaxie/beego/orm"
  14. )
  15. //检测时间隔管理
  16. type CheckAreaMgr struct {
  17. DeviceBaseModel
  18. //SCD文件ID
  19. ScdId int64
  20. //电压等级定义
  21. VoltageLevelDef map[string]int
  22. //设备类型定义
  23. DeviceTypeDef map[string]int
  24. CacheAreaID map[string]int64
  25. CacheAreaIDByIedNameNo map[string]int
  26. //检测模型列表
  27. CheckModelList []orm.Params
  28. //模型内装置关系定义
  29. CheckModelDef sync.Map
  30. CacheLock sync.RWMutex
  31. }
  32. type T_data_check_area struct {
  33. Id int64 `orm:"pk"`
  34. AreaName string
  35. ScdId int64
  36. VoltageLevel int
  37. AreaType string
  38. ModelId int
  39. Cr int // '创建人' ,
  40. Ct string `orm:"-"` // '创建时间' ,
  41. Ur int // '更新人' ,
  42. Ut string `orm:"-"` // '更新时间'
  43. }
  44. type t_data_check_area_ied struct {
  45. Id int64 `orm:"pk"`
  46. AreaId int64
  47. IedName string
  48. IedType string
  49. ScdId int64
  50. PType string
  51. Cr int // '创建人' ,
  52. Ct string `orm:"-"` // '创建时间' ,
  53. Ur int // '更新人' ,
  54. Ut string `orm:"-"` // '更新时间'
  55. }
  56. func init() {
  57. orm.RegisterModel(new(T_data_check_area))
  58. orm.RegisterModel(new(t_data_check_area_ied))
  59. }
  60. func (c *CheckAreaMgr) Init(scdid int64) {
  61. c.VoltageLevelDef = map[string]int{}
  62. c.DeviceTypeDef = map[string]int{}
  63. c.CacheAreaIDByIedNameNo = map[string]int{}
  64. c.CacheAreaID = map[string]int64{}
  65. c.CacheLock = sync.RWMutex{}
  66. c.ScdId = scdid
  67. db := orm.NewOrm()
  68. rowset := []orm.Params{}
  69. db.Raw("select * from global_const_code where parentcode=?", "voltage_level").Values(&rowset)
  70. for _, row := range rowset {
  71. vl := strings.ToLower(tools.IsEmpty(row["code"]))
  72. id, _ := strconv.ParseInt(tools.IsEmpty(row["id"]), 10, 32)
  73. c.VoltageLevelDef[strings.ReplaceAll(vl, "v_level_", "")] = int(id)
  74. }
  75. db.Raw("select * from global_const_code where parentcode=?", "device_type").Values(&rowset)
  76. for _, row := range rowset {
  77. vl := tools.IsEmpty(row["code"])
  78. c.DeviceTypeDef[vl] = 1
  79. }
  80. v, _ := GetSysParamValue("OtherIedNameList", "")
  81. otherIedNameList = map[string]bool{}
  82. if v != "" {
  83. vs := strings.Split(v, ",")
  84. for _, vv := range vs {
  85. otherIedNameList[vv] = true
  86. }
  87. }
  88. //先清除ied与间隔关联关系
  89. clearSql := "delete from t_data_check_area_ied where area_id in(select id from t_data_check_area where scd_id=?)"
  90. _, err := db.Raw(clearSql, c.ScdId).Exec()
  91. if err != nil {
  92. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{c.ScdId}))
  93. }
  94. clearSql = "delete from t_data_check_area where scd_id=?"
  95. _, err = db.Raw(clearSql, c.ScdId).Exec()
  96. if err != nil {
  97. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{c.ScdId}))
  98. }
  99. //获取当前scd信息中获取到对应的电压等级id
  100. /*
  101. scdMgr := new(ScdMgr)
  102. scdinfo, _ := scdMgr.One(fmt.Sprintf("%d", c.ScdId))
  103. stationid := tools.IsEmpty(scdinfo["station_id"])
  104. volid := 0
  105. if stationid != "" {
  106. basearea := new(BasicArea)
  107. stationonof, _ := basearea.One(stationid)
  108. volid = stationonof.AreaLevel
  109. }
  110. */
  111. tmplist, _ := new(SysCheckModelMgr).GetModelsByVolid(2)
  112. scdModels, _, _ := new(TaskMgr).GetModelsByScdID(c.ScdId)
  113. ms := map[string]interface{}{}
  114. for _, row := range scdModels {
  115. ms[tools.IsEmpty(row["model_id"])] = row
  116. }
  117. for _, row := range tmplist {
  118. modelid := tools.IsEmpty(row["id"])
  119. if ms[modelid] != nil {
  120. c.CheckModelList = append(c.CheckModelList, row)
  121. }
  122. }
  123. logger.Logger.Debug(fmt.Sprintf("任务的模型列表:%+v", c.CheckModelList))
  124. ms = nil
  125. tmplist = nil
  126. }
  127. //保存指定间隔所属的电压等级
  128. func (c *CheckAreaMgr) SetVoltageLevel(id string, voltagelevel int) error {
  129. db := orm.NewOrm()
  130. _, err := db.Raw("update t_data_check_area set voltage_level=? where id=?", voltagelevel, id).Exec()
  131. return err
  132. }
  133. //修改指定间隔的名称
  134. func (c *CheckAreaMgr) UpdateName(scdid int64, area_id int, name string) error {
  135. db := orm.NewOrm()
  136. areaM := T_data_check_area{Id: int64(area_id), ScdId: scdid}
  137. err := db.Read(&areaM)
  138. if err != nil {
  139. logger.Logger.Error(err)
  140. return err
  141. }
  142. areaM.AreaName = name
  143. _, err = db.Update(&areaM)
  144. if err != nil {
  145. logger.Logger.Error(err)
  146. }
  147. return err
  148. }
  149. //修改指定IED的所属间隔
  150. func (c *CheckAreaMgr) UpdateIedArea(scdid int64, iedname string, area_id int) error {
  151. db := orm.NewOrm()
  152. _, err := db.Raw("update t_data_check_area_ied set area_id=? where scd_id=? and ied_name=?", area_id, scdid, iedname).Exec()
  153. return err
  154. }
  155. //获取指定scd的间隔信息
  156. func (c *CheckAreaMgr) GetAreaList(scdid int64) ([]orm.Params, error) {
  157. db := orm.NewOrm()
  158. sql := "select t.*,(select count(1) from t_data_check_area_ied where area_id=t.id) iedcount from t_data_check_area t where t.scd_id=? order by t.name"
  159. rowset := []orm.Params{}
  160. _, err := db.Raw(sql, scdid).Values(&rowset)
  161. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid})
  162. if err != nil {
  163. logger.Logger.Error(err, sqllog)
  164. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  165. } else {
  166. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  167. }
  168. return rowset, nil
  169. }
  170. //获取指定scd和电压等级的间隔信息
  171. func (c *CheckAreaMgr) GetAreaListByVol(scdid int64, vl, linkstyleid int) ([]orm.Params, error) {
  172. db := orm.NewOrm()
  173. sql := "select t1.id model_id, t1.model_name,t1.vol_id,g1.name vol_name,t1.line_link_style,ls.name,t.id area_id, t.area_name,t.ut,t.ur from t_data_check_area t right join t_data_model_defualt t1 on t.model_id=t1.id left join t_data_link_style ls on t1.line_link_style=ls.id left join global_const_code g1 on t1.vol_id=g1.id and g1.parentcode='voltage_level' where t.scd_id=? "
  174. params := []interface{}{scdid}
  175. if vl > 0 {
  176. sql = sql + " and t1.vol_id=? "
  177. params = append(params, vl)
  178. }
  179. if linkstyleid > 0 {
  180. sql = sql + " and t1.line_link_style=? "
  181. params = append(params, linkstyleid)
  182. }
  183. rowset := []orm.Params{}
  184. _, err := db.Raw(sql+" order by t1.vol_id,t1.line_link_style,t1.id", params).Values(&rowset)
  185. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid, vl})
  186. if err != nil {
  187. logger.Logger.Error(err, sqllog)
  188. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  189. } else {
  190. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  191. }
  192. return rowset, nil
  193. }
  194. //获取指定间隔下的IED列表
  195. func (c *CheckAreaMgr) GetIedList(scdid int64, areaid int) ([]orm.Params, error) {
  196. db := orm.NewOrm()
  197. sql := "select t1.* from t_data_check_area t,t_data_check_area_ied t1 where t.scd_id=? and t.id=t1.area_id "
  198. sqlParamters := []interface{}{}
  199. sqlParamters = append(sqlParamters, scdid)
  200. if areaid > 0 {
  201. sql = sql + " and t1.area_id=?"
  202. sqlParamters = append(sqlParamters, areaid)
  203. }
  204. scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
  205. if serr != nil {
  206. return nil, serr
  207. }
  208. if scdXmlObj == nil {
  209. return nil, errors.New("无效的SCD")
  210. }
  211. rowset := []orm.Params{}
  212. _, err := db.Raw(sql, sqlParamters).Values(&rowset)
  213. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
  214. if err != nil {
  215. logger.Logger.Error(err, sqllog)
  216. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  217. } else {
  218. scdNode := new(ScdNode)
  219. for i, row := range rowset {
  220. iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), tools.IsEmpty(row["ied_name"]))
  221. if iedObj == nil {
  222. continue
  223. }
  224. rowset[i]["attr_name"] = iedObj.Name
  225. rowset[i]["attr_desc"] = iedObj.Desc
  226. rowset[i]["attr_config_version"] = iedObj.ConfigVersion
  227. rowset[i]["attr_type"] = iedObj.Type
  228. rowset[i]["attr_manufacturer"] = iedObj.Manufacturer
  229. rowset[i]["ied_id"] = iedObj.NodeId
  230. }
  231. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  232. }
  233. return rowset, nil
  234. }
  235. //更新指定间隔下的装置定义
  236. func (c *CheckAreaMgr) UpdateIeds(scdid int64, areaid int, ieds string) error {
  237. db := orm.NewOrm()
  238. iedlist := strings.Split(ieds, ",")
  239. _, err := db.Raw("delete from t_data_check_area_ied where scd_id=? and area_id=?", scdid, areaid).Exec()
  240. if err != nil {
  241. logger.Logger.Error(err)
  242. return err
  243. }
  244. for _, row := range iedlist {
  245. _, err = db.Raw("insert into t_data_check_area_ied(scd_id,area_id,ied_name)values(?,?,?)", scdid, areaid, row).Exec()
  246. if err != nil {
  247. logger.Logger.Error(err)
  248. break
  249. }
  250. }
  251. return err
  252. }
  253. //获取指定SCD的IED类型列表
  254. func (c *CheckAreaMgr) GetIedTypeList(scdid int64) ([]orm.Params, error) {
  255. db := orm.NewOrm()
  256. sql := "select t2.* from t_data_check_area_ied t1,global_const_code t2 where t1.scd_id=? and t1.ied_type=t2.code and t2.parentcode='device_type' group by t1.ied_type "
  257. sqlParamters := []interface{}{}
  258. rowset := []orm.Params{}
  259. sqlParamters = append(sqlParamters, scdid)
  260. _, err := db.Raw(sql, sqlParamters).Values(&rowset)
  261. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
  262. if err != nil {
  263. logger.Logger.Error(err, sqllog)
  264. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  265. }
  266. return rowset, nil
  267. }
  268. func (c *CheckAreaMgr) One(id string) (interface{}, error) {
  269. db := orm.NewOrm()
  270. idInt, err := strconv.ParseInt(id, 10, 64)
  271. if err != nil {
  272. return nil, err
  273. }
  274. areaM := T_data_check_area{Id: idInt}
  275. err = db.Read(&areaM)
  276. if err == nil {
  277. return areaM, nil
  278. }
  279. return nil, err
  280. }
  281. //重置scd的间隔信息
  282. func (c *CheckAreaMgr) Reset() error {
  283. dbo := orm.NewOrm()
  284. dbo.Raw("delete from t_data_check_area where scd_id=?", c.ScdId).Exec()
  285. dbo.Raw("delete from t_data_check_area_ied where scd_id=?", c.ScdId).Exec()
  286. c.ParseModelArea()
  287. logdesc := fmt.Sprintf("重置SCD[%d]检测模型间隔成功", c.ScdId)
  288. new(SystemLog).Success(enum.AuditType_check_task, enum.LogType_bind, enum.OptEventType_Bus, enum.OptEventLevel_Mid, logdesc, c.GetUserInfo())
  289. return nil
  290. }
  291. var areaCheckInfo = sync.Map{}
  292. //获取解析模型需要的基础数据信息
  293. func (c *CheckAreaMgr) getAreaCheckInfo() (*node_attr.SCL, []orm.Params, string, error) {
  294. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  295. if v, h := areaCheckInfo.Load(key); h {
  296. v1 := v.([]interface{})
  297. return v1[0].(*node_attr.SCL), v1[1].([]orm.Params), v1[2].(string), nil
  298. }
  299. arealist := []orm.Params{}
  300. db := orm.NewOrm()
  301. _, err := db.Raw("select id,area_name,area_type,model_id from t_data_check_area where scd_id=?", c.ScdId).Values(&arealist)
  302. if err != nil {
  303. logger.Logger.Error(err)
  304. return nil, nil, "", err
  305. }
  306. scdNodeRule := new(ScdNodeRule)
  307. area_ruleid := ""
  308. area_ruleList, _, _ := scdNodeRule.GetDefList(map[string]interface{}{"check_name": "间隔装置与检查模型不符"}, 1, 1)
  309. if len(area_ruleList) > 0 {
  310. area_ruleid = tools.IsEmpty(area_ruleList[0]["id"])
  311. }
  312. if area_ruleid == "" {
  313. return nil, nil, "", errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  314. }
  315. scdParseMgr := new(ScdParse)
  316. scdXmlObj, serr := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  317. if serr != nil {
  318. return nil, nil, "", serr
  319. }
  320. if scdXmlObj == nil {
  321. return nil, nil, "", errors.New("无效的SCD")
  322. }
  323. areaCheckInfo.Store(key, []interface{}{scdXmlObj, arealist, area_ruleid})
  324. return scdXmlObj, arealist, area_ruleid, nil
  325. }
  326. //检测装置端子分析:检测间隔装置关系正确性(已废弃)
  327. func (c *CheckAreaMgr) CheckAreaIedRelation() error {
  328. // 获取当前scd中需要检查的间隔
  329. scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
  330. db := orm.NewOrm()
  331. if err != nil {
  332. logger.Logger.Error(err)
  333. return err
  334. }
  335. if area_ruleid == "" {
  336. return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  337. }
  338. if scdXmlObj == nil {
  339. return errors.New("无效的SCD")
  340. }
  341. scdNodeRule := new(ScdNodeRule)
  342. scdNode := new(ScdNode)
  343. model_refs := map[string][]orm.Params{} //模型定义的装置关系定义
  344. area_ieds := map[string][]orm.Params{} //间隔下的装置列表
  345. iedRelationMgr := new(SysCheckModelIedRelationMgr)
  346. for _, row := range arealist {
  347. //获取间隔标准装置及关系
  348. modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
  349. //area_name := tools.IsEmpty(row["area_name"])
  350. //area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
  351. area_id := tools.IsEmpty(row["id"])
  352. s, err := iedRelationMgr.GetListByModelid(modelid)
  353. if err != nil {
  354. logger.Logger.Error(err)
  355. return err
  356. }
  357. if len(s) == 0 {
  358. return errors.New(fmt.Sprintf("模型%d还未配置装置关系", modelid))
  359. }
  360. model_refs[fmt.Sprintf("%d", modelid)] = s
  361. /*
  362. hasIeds := map[string]bool{}
  363. for _, row1 := range s {
  364. iedname := tools.IsEmpty(row1["from_ied_code"])
  365. if !hasIeds[iedname] {
  366. hasIeds[iedname] = true
  367. }
  368. iedname = tools.IsEmpty(row1["to_ied_code"])
  369. if !hasIeds[iedname] {
  370. hasIeds[iedname] = true
  371. }
  372. }
  373. */
  374. s1 := []orm.Params{}
  375. _, err = db.Raw("select ied_name from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
  376. if err != nil {
  377. logger.Logger.Error(err)
  378. return err
  379. }
  380. if len(s) == 0 {
  381. return errors.New(fmt.Sprintf("间隔%s未发现任何装置", tools.IsEmpty(row["area_name"])))
  382. }
  383. area_ieds[area_id] = s1
  384. }
  385. //装置关联关系分析
  386. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  387. HasAreaJ := false
  388. for _, row := range arealist {
  389. area_name := tools.IsEmpty(row["area_name"])
  390. areaCode := tools.IsEmpty(row["area_type"]) //间隔模型类型
  391. area_id := tools.IsEmpty(row["id"])
  392. if areaCode == "J" {
  393. HasAreaJ = true
  394. modelid := tools.IsEmpty(row["model_id"])
  395. c.cJ(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PE", area_ruleid)
  396. c.cJ(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PJ", area_ruleid)
  397. c.cJ(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PK", area_ruleid)
  398. c.cJ(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PF", area_ruleid)
  399. }
  400. }
  401. for _, row := range arealist {
  402. area_name := tools.IsEmpty(row["area_name"])
  403. areaCode := tools.IsEmpty(row["area_type"]) //间隔模型类型
  404. area_id := tools.IsEmpty(row["id"])
  405. modelid := tools.IsEmpty(row["model_id"])
  406. if areaCode == "J" {
  407. continue
  408. }
  409. if areaCode == "L" {
  410. //线路间隔
  411. c.cL(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], area_ruleid)
  412. }
  413. if areaCode == "T" {
  414. //变压器齐间隔
  415. c.cT(scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], area_ruleid, HasAreaJ)
  416. }
  417. }
  418. scdNodeRule.CheckFinish()
  419. scdNodeRule.Flush()
  420. return nil
  421. }
  422. //检测装置功能分析
  423. func (c *CheckAreaMgr) CheckIedFunc() error {
  424. return nil
  425. }
  426. //检测装置端子分析
  427. func (c *CheckAreaMgr) CheckIedFcda() error {
  428. scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
  429. if err != nil {
  430. logger.Logger.Error(err)
  431. return err
  432. }
  433. if area_ruleid == "" {
  434. return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  435. }
  436. if scdXmlObj == nil {
  437. return errors.New("无效的SCD")
  438. }
  439. db := orm.NewOrm()
  440. //获取当前站的各电压等级
  441. volRows := []orm.Params{}
  442. _, 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)
  443. if err != nil {
  444. logger.Logger.Error(err)
  445. return err
  446. }
  447. if len(volRows) == 0 {
  448. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  449. return errors.New("该scd未发现任何电压等级的装置")
  450. }
  451. volMap := map[string]string{}
  452. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  453. if len(volRows) == 2 {
  454. volMap["middle"] = ""
  455. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  456. } else {
  457. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  458. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  459. }
  460. scdNodeRule := new(ScdNodeRule)
  461. scdNodeMgr := new(ScdNode)
  462. //当前装置的所有信号接收端子列表
  463. var getIedExtRefs = func(iedname string) map[string]*node_attr.NExtRef {
  464. iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
  465. if iedObj == nil {
  466. return nil
  467. }
  468. fcdaObjList := map[string]*node_attr.NExtRef{}
  469. for _, t1 := range iedObj.AccessPoint {
  470. if t1.Server == nil || len(t1.Server.LDevice) == 0 {
  471. continue
  472. }
  473. for _, ld := range t1.Server.LDevice {
  474. if ld.LN0 != nil && ld.LN0.Inputs != nil {
  475. for _, t2 := range ld.LN0.Inputs.ExtRef {
  476. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  477. if doi == nil {
  478. continue
  479. }
  480. fcdaObjList[doi.(*node_attr.NDOI).Desc] = t2
  481. }
  482. }
  483. for _, ln := range ld.LN {
  484. if ln.Inputs == nil {
  485. continue
  486. }
  487. for _, t2 := range ln.Inputs.ExtRef {
  488. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  489. if doi == nil {
  490. continue
  491. }
  492. fcdaObjList[doi.(*node_attr.NDOI).Desc] = t2
  493. }
  494. }
  495. }
  496. }
  497. return fcdaObjList
  498. }
  499. //当前装置的所有信号发送端子列表
  500. var getIedFcdas = func(iedname string) map[string]*node_attr.NFCDA {
  501. iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
  502. if iedObj == nil {
  503. return nil
  504. }
  505. fcdaObjList := map[string]*node_attr.NFCDA{}
  506. for _, t1 := range iedObj.AccessPoint {
  507. if t1.Server == nil || len(t1.Server.LDevice) == 0 {
  508. continue
  509. }
  510. for _, ld := range t1.Server.LDevice {
  511. if ld.LN0 != nil && len(ld.LN0.DataSet) > 0 {
  512. for _, t2 := range ld.LN0.DataSet {
  513. for _, t3 := range t2.FCDA {
  514. re, _ := scdNodeRule.IedFcdaExist(iedname, t3.LdInst, t3.LnClass, t3.LnInst, t3.Prefix, t3.DoName, t3.DaName)
  515. if re == nil {
  516. continue
  517. }
  518. doi := re.(*node_attr.NDOI)
  519. fcdaObjList[doi.Desc] = t3
  520. }
  521. }
  522. }
  523. }
  524. }
  525. return fcdaObjList
  526. }
  527. //从装置类型code中解析出类型代码和电压等级
  528. var getIedTypeAndVolCode = func(ied_type string) (string, string) {
  529. tmp := strings.Split(ied_type, "#")
  530. ied_type = tmp[0]
  531. vol := ""
  532. if len(tmp) == 2 {
  533. vol = tmp[1] //电压级别
  534. }
  535. return ied_type, vol
  536. }
  537. //从间隔装置中过滤出指定类型的IED
  538. var filterAreaIeds = func(ied_type, volLevelCode string, s1 []orm.Params) []orm.Params {
  539. iedlst := []orm.Params{}
  540. if volLevelCode == "" {
  541. for _, r := range s1 {
  542. if strings.HasPrefix(tools.IsEmpty(r["ied_name"]), ied_type) {
  543. iedlst = append(iedlst, r)
  544. }
  545. }
  546. } else {
  547. tmpLst := map[string]orm.Params{}
  548. for _, r := range s1 {
  549. iedname := tools.IsEmpty(r["ied_name"])
  550. if strings.HasPrefix(iedname, ied_type) {
  551. tmpLst[iedname] = r
  552. }
  553. }
  554. h, m, l := c.getIedListByVol(ied_type, tmpLst, volMap)
  555. if volLevelCode == "H" {
  556. iedlst = h
  557. }
  558. if volLevelCode == "M" {
  559. iedlst = m
  560. }
  561. if volLevelCode == "L" {
  562. iedlst = l
  563. }
  564. }
  565. return iedlst
  566. }
  567. //iedRelationMgr := new(SysCheckModelIedRelationMgr)
  568. for _, row := range arealist {
  569. //获取间隔标准装置及关系
  570. modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
  571. area_name := tools.IsEmpty(row["area_name"])
  572. //area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
  573. area_id := tools.IsEmpty(row["id"])
  574. //获取该间隔模型配置的所有端子关系列表
  575. tmpMgr := new(SysCheckModelFcdaRalationMgr)
  576. tmpMgr.Model.ModelId = modelid
  577. funclist, _ := tmpMgr.GetModelAllFcdaRef()
  578. if funclist == nil {
  579. continue
  580. }
  581. if len(funclist) == 0 {
  582. logger.Logger.Error(errors.New(fmt.Sprintf("模型%d还未配置装置关系", modelid)))
  583. continue
  584. }
  585. //获取该间隔下该类型的装置
  586. s1 := []orm.Params{}
  587. _, err = db.Raw("select ied_name from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
  588. //循环处理关联关系
  589. for ied_type, fromrowlist := range funclist {
  590. //找出信号输出装置
  591. outiedlist := map[string][]orm.Params{}
  592. for _, r := range fromrowlist {
  593. fromiedcode := tools.IsEmpty(r["from_ied_code"])
  594. ied_type, vol := getIedTypeAndVolCode(fromiedcode)
  595. outiedlist2 := filterAreaIeds(ied_type, vol, s1)
  596. for _, iedrow := range outiedlist2 {
  597. iedname := tools.IsEmpty(iedrow["ied_name"])
  598. if outiedlist[iedname] == nil {
  599. outiedlist[iedname] = []orm.Params{}
  600. }
  601. outiedlist[iedname] = append(outiedlist[iedname], r)
  602. }
  603. }
  604. if len(outiedlist) == 0 {
  605. continue
  606. }
  607. ied_type, vol := getIedTypeAndVolCode(ied_type)
  608. iedlst := filterAreaIeds(ied_type, vol, s1)
  609. for _, ied := range iedlst {
  610. iedname := tools.IsEmpty(ied["ied_name"])
  611. extreflist := getIedExtRefs(iedname)
  612. for outiedname, refrow := range outiedlist {
  613. outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
  614. //检查是否有错误和缺失的端子
  615. for _, r := range refrow {
  616. extref_name := tools.IsEmpty(r["to_fcda_name"])
  617. fcda_name := tools.IsEmpty(r["from_fcda_name"])
  618. extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
  619. fcda_name_exp := tools.IsEmpty(r["from_fcda_match_exp"])
  620. funcExist := false //设计的功能是否存在
  621. extrefObj := new(node_attr.NExtRef)
  622. for desc, item := range extreflist {
  623. rex, err := regexp.Compile(extref_name_exp)
  624. if err != nil {
  625. logger.Logger.Error(err, "无效的正则表达式:"+extref_name_exp)
  626. return err
  627. }
  628. if rex.MatchString(desc) {
  629. funcExist = true
  630. extrefObj = item
  631. break
  632. }
  633. }
  634. if !funcExist {
  635. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  636. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  637. parse_result := ""
  638. if !funcExist {
  639. parse_result = fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, iedname, extref_name)
  640. }
  641. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  642. "ied_name": iedname,
  643. "ied_desc": iedObj.Desc,
  644. "out_ied_name": outiedname,
  645. "out_ied_desc": outIedObj.Desc,
  646. "fcda_desc": extref_name,
  647. "fcda_addr": "",
  648. "out_fcda_desc": fcda_name,
  649. "out_fcda_addr": "",
  650. "error_type": "3",
  651. }
  652. //检查未通过
  653. scdNodeRule.AppendFcdaCheckResult(re)
  654. } else {
  655. //检查端子是否关联正确
  656. fcda2Exist := false
  657. fcdaObj := new(node_attr.NFCDA)
  658. for desc, item := range outiedFcdaList {
  659. rex, err := regexp.Compile(fcda_name_exp)
  660. if err != nil {
  661. logger.Logger.Error(err, "无效的正则表达式:"+fcda_name_exp)
  662. return err
  663. }
  664. if rex.MatchString(desc) {
  665. fcda2Exist = true
  666. fcdaObj = item
  667. break
  668. }
  669. }
  670. if fcda2Exist && (extrefObj.LdInst != fcdaObj.LdInst ||
  671. extrefObj.LnInst != fcdaObj.LnInst ||
  672. extrefObj.LnClass != fcdaObj.LnClass ||
  673. extrefObj.Prefix != fcdaObj.Prefix ||
  674. extrefObj.DoName != fcdaObj.DoName) {
  675. //不正确
  676. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  677. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  678. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误", area_name, iedname, extref_name, outiedname, fcda_name)
  679. daname := ""
  680. if fcdaObj.DaName != "" {
  681. daname = "." + fcdaObj.DaName
  682. }
  683. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  684. "ied_name": iedname,
  685. "ied_desc": iedObj.Desc,
  686. "out_ied_name": outiedname,
  687. "out_ied_desc": outIedObj.Desc,
  688. "fcda_desc": extref_name,
  689. "fcda_addr": extrefObj.IntAddr,
  690. "out_fcda_desc": fcda_name,
  691. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", fcdaObj.LdInst, fcdaObj.Prefix, fcdaObj.LnClass, fcdaObj.LnInst, fcdaObj.DoName, daname),
  692. "error_type": "2",
  693. }
  694. //检查未通过
  695. scdNodeRule.AppendFcdaCheckResult(re)
  696. }
  697. }
  698. }
  699. //检查是否有多余(SCD中有不存在于设计中)的端子
  700. for extrefdesc, r := range extreflist { //scd中的端子关系
  701. extref_name := ""
  702. fcda_name := ""
  703. isHave := false
  704. for _, r1 := range refrow { //设计的端子关系
  705. extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
  706. rex, err := regexp.Compile(extref_name_exp)
  707. if err != nil {
  708. logger.Logger.Error(err)
  709. return err
  710. }
  711. if rex.MatchString(extrefdesc) {
  712. //端子存在
  713. isHave = true
  714. break
  715. }
  716. }
  717. if !isHave {
  718. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  719. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  720. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s在设计中不存在", area_name, iedname, extref_name)
  721. daname := ""
  722. if r.DaName != "" {
  723. daname = "." + r.DaName
  724. }
  725. doi := scdNodeRule.IedIntAddrExist(iedname, r.IntAddr)
  726. if doi != nil {
  727. extref_name = doi.(*node_attr.NDOI).Desc
  728. }
  729. doi, _ = scdNodeRule.IedFcdaExist(outiedname, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
  730. if doi != nil {
  731. fcda_name = doi.(*node_attr.NDOI).Desc
  732. }
  733. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  734. "ied_name": iedname,
  735. "ied_desc": iedObj.Desc,
  736. "out_ied_name": outiedname,
  737. "out_ied_desc": outIedObj.Desc,
  738. "fcda_desc": extref_name,
  739. "fcda_addr": r.IntAddr,
  740. "out_fcda_desc": fcda_name,
  741. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName, daname),
  742. "error_type": "1",
  743. }
  744. //检查未通过
  745. scdNodeRule.AppendFcdaCheckResult(re)
  746. }
  747. }
  748. }
  749. }
  750. }
  751. }
  752. scdNodeRule.CheckFinish()
  753. scdNodeRule.Flush()
  754. return nil
  755. }
  756. //解析模型间隔。根据模型定义解析出间隔中的装置
  757. func (c *CheckAreaMgr) ParseModelArea() {
  758. c.Init(c.ScdId)
  759. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  760. areaCheckInfo.Delete(key)
  761. // 取得当前scd所有ied及名称解析结果
  762. dbo := orm.NewOrm()
  763. 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"
  764. iedlst := []orm.Params{}
  765. _, err := dbo.Raw(sql, c.ScdId).Values(&iedlst)
  766. if err != nil {
  767. logger.Logger.Error(err)
  768. return
  769. }
  770. logger.Logger.Debug(fmt.Sprintf("=====总装置数:%d", len(iedlst)))
  771. iedMap := map[string]orm.Params{}
  772. for _, r := range iedlst {
  773. iedMap[tools.IsEmpty(r["ied_name"])] = r
  774. }
  775. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  776. HasAreaJ := false
  777. for _, row := range c.CheckModelList {
  778. areaCode := tools.IsEmpty(row["area_type_code"])
  779. if areaCode == "J" {
  780. HasAreaJ = true
  781. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  782. //modelname := tools.IsEmpty(row["model_name"])
  783. iedtypes := tools.IsEmpty(row["ied_types"])
  784. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  785. c.pJ(modelid, volcode, iedtypes, iedMap, "PE")
  786. c.pJ(modelid, volcode, iedtypes, iedMap, "PJ")
  787. c.pJ(modelid, volcode, iedtypes, iedMap, "PK")
  788. c.pJ(modelid, volcode, iedtypes, iedMap, "PF")
  789. }
  790. }
  791. for _, row := range c.CheckModelList {
  792. //逐一分析模型定义
  793. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  794. modelname := tools.IsEmpty(row["model_name"])
  795. iedtypes := tools.IsEmpty(row["ied_types"])
  796. //模型对应的间隔代码
  797. /*
  798. S 站用变压器
  799. C 电容器
  800. B 断路器
  801. K 母分
  802. J 母联
  803. M 母线
  804. X 电抗器
  805. L 线路
  806. T 主变压器
  807. */
  808. areaCode := tools.IsEmpty(row["area_type_code"])
  809. //模型对应的电压等级
  810. //10:10KV 35:35KV 66:66KV 11:110KV 22:220KV 50:500KV 75:750KV 33:330KV T0:1000KV
  811. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  812. if modelname == "" || iedtypes == "" {
  813. continue
  814. }
  815. //母联间隔已经提前分析,如果没有母联间隔时,主变间隔中不包含母联终端装置
  816. if areaCode == "J" {
  817. continue
  818. }
  819. //获取模型内中装备关系定义
  820. //主变间隔分析:需要查站内该电压等级下的高中低压侧装置或者高低压装置组成一个间隔,以主变保护装置(PT)为起始
  821. if areaCode == "T" {
  822. c.pT(modelid, iedtypes, iedMap, HasAreaJ)
  823. }
  824. //线路保护间隔分析:以线路保护测控装置(PL)为开始分析
  825. if areaCode == "L" {
  826. c.pL(modelid, volcode, iedtypes, iedMap)
  827. }
  828. }
  829. }
  830. //变压器间隔分析
  831. func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Params, HasAreaJ bool) {
  832. scdParseMgr := new(ScdParse)
  833. db := orm.NewOrm()
  834. //获取当前站的各电压等级
  835. volRows := []orm.Params{}
  836. _, 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)
  837. if err != nil {
  838. logger.Logger.Error(err)
  839. return
  840. }
  841. if len(volRows) == 0 {
  842. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  843. return
  844. }
  845. volMap := map[string]string{}
  846. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  847. if len(volRows) == 2 {
  848. volMap["middle"] = ""
  849. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  850. } else {
  851. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  852. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  853. }
  854. //判断是否将各电压等级的保护装置合并还是分开的间隔
  855. //如果存在高中低压的保护装置,则说明是分开的主变间隔
  856. //isMarge := true // 默认为合并的主变间隔
  857. for _, row := range ieds {
  858. if tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "T" {
  859. continue
  860. }
  861. //pmIedName := ""
  862. //mmIedName := ""
  863. pl_iedname := tools.IsEmpty(row["ied_name"])
  864. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  865. //添加间隔数据
  866. dbdata := T_data_check_area{
  867. ModelId: modelid,
  868. ScdId: c.ScdId,
  869. AreaType: "T",
  870. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  871. }
  872. newid, err := db.Insert(&dbdata)
  873. if err != nil {
  874. logger.Logger.Error(err)
  875. return
  876. }
  877. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  878. insvalues := []string{}
  879. inAreaIedName := pl_iedname
  880. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "T"))
  881. //合智一体IMT/MIT,分高中低压
  882. h, m, l := c.getIedListByVol("IMT", ieds, volMap)
  883. h = append(h, m...)
  884. h = append(h, l...)
  885. for _, r := range h {
  886. inAreaIedName = tools.IsEmpty(r["ied_name"])
  887. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  888. lastChar := tmpIednameParts[7]
  889. if lastChar == iednameParts[7] {
  890. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "IM", "T"))
  891. }
  892. }
  893. h, m, l = c.getIedListByVol("MIT", ieds, volMap)
  894. h = append(h, m...)
  895. h = append(h, l...)
  896. for _, r := range h {
  897. inAreaIedName = tools.IsEmpty(r["ied_name"])
  898. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  899. lastChar := tmpIednameParts[7]
  900. if lastChar == iednameParts[7] {
  901. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "MI", "T"))
  902. }
  903. }
  904. //母联智能终端IE需要分高中压,无低压侧
  905. if HasAreaJ {
  906. h, m, l = c.getIedListByVol("IE", ieds, volMap)
  907. for _, r := range h {
  908. //高压侧,AB套必须与PT装置相同
  909. inAreaIedName = tools.IsEmpty(r["ied_name"])
  910. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  911. lastChar := tmpIednameParts[7]
  912. if lastChar == iednameParts[7] {
  913. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "E"))
  914. }
  915. }
  916. for _, r := range m {
  917. //中压侧
  918. inAreaIedName = tools.IsEmpty(r["ied_name"])
  919. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  920. lastChar := tmpIednameParts[7]
  921. if lastChar == "" || lastChar == iednameParts[7] {
  922. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "E"))
  923. }
  924. }
  925. }
  926. //合并单元MT分高中低压侧;低压侧无关联母线合并单元MM
  927. h, m, l = c.getIedListByVol("MT", ieds, volMap)
  928. h = append(h, m...)
  929. h = append(h, l...)
  930. for _, r := range h {
  931. inAreaIedName = tools.IsEmpty(r["ied_name"])
  932. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  933. lastChar := tmpIednameParts[7]
  934. if lastChar == iednameParts[7] {
  935. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "T"))
  936. }
  937. }
  938. //测控装置CT分高中低压侧,且可能是多套合并单元MT共用,既不分AB套
  939. h, m, l = c.getIedListByVol("CT", ieds, volMap)
  940. h = append(h, m...)
  941. h = append(h, l...)
  942. for _, r := range h {
  943. inAreaIedName = tools.IsEmpty(r["ied_name"])
  944. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  945. lastChar := tmpIednameParts[7]
  946. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  947. //高中低压电压等级相同的
  948. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  949. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "C", "T"))
  950. }
  951. }
  952. //智能终端(IB:开关\IT:分支\IF:分段)分高中低压侧
  953. h, m, l = c.getIedListByVol("IB", ieds, volMap)
  954. h = append(h, m...)
  955. h = append(h, l...)
  956. for _, r := range h {
  957. inAreaIedName = tools.IsEmpty(r["ied_name"])
  958. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  959. lastChar := tmpIednameParts[7]
  960. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  961. //高中低压电压等级相同的
  962. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  963. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "B"))
  964. }
  965. }
  966. h, m, l = c.getIedListByVol("IT", ieds, volMap)
  967. h = append(h, m...)
  968. h = append(h, l...)
  969. for _, r := range h {
  970. inAreaIedName = tools.IsEmpty(r["ied_name"])
  971. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  972. lastChar := tmpIednameParts[7]
  973. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  974. //高中低压电压等级相同的
  975. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  976. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "T"))
  977. }
  978. }
  979. h, m, l = c.getIedListByVol("IF", ieds, volMap)
  980. h = append(h, m...)
  981. h = append(h, l...)
  982. for _, r := range h {
  983. inAreaIedName = tools.IsEmpty(r["ied_name"])
  984. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  985. lastChar := tmpIednameParts[7]
  986. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  987. //高中低压电压等级相同的
  988. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  989. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "F"))
  990. }
  991. }
  992. //母线保护PM及母线合并单元MM,可能是多套合并单元MT共用,既不分AB套;低压侧智能终端无关联母线保护
  993. h, m, l = c.getIedListByVol("PM", ieds, volMap)
  994. for _, r := range h {
  995. //高压侧,AB套必须与PT装置相同
  996. inAreaIedName = tools.IsEmpty(r["ied_name"])
  997. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  998. lastChar := tmpIednameParts[7]
  999. if lastChar == iednameParts[7] {
  1000. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1001. //MM装置
  1002. mmIedName := c.getMMName(tmpIednameParts, ieds, iednameParts[7])
  1003. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, mmIedName, "M", "M"))
  1004. break
  1005. }
  1006. }
  1007. for _, r := range m {
  1008. //中压侧
  1009. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1010. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1011. lastChar := tmpIednameParts[7]
  1012. if lastChar == "" || lastChar == iednameParts[7] {
  1013. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1014. //MM装置
  1015. mmIedName := c.getMMName(tmpIednameParts, ieds, iednameParts[7])
  1016. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, mmIedName, "M", "M"))
  1017. break
  1018. }
  1019. }
  1020. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1021. if err != nil {
  1022. logger.Logger.Error(err)
  1023. return
  1024. }
  1025. }
  1026. }
  1027. //线路间隔分析
  1028. //vol:电压等级
  1029. func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1030. scdParseMgr := new(ScdParse)
  1031. //scdNodeMgr := new(ScdNode)
  1032. db := orm.NewOrm()
  1033. //scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1034. for _, row := range ieds {
  1035. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "L" {
  1036. continue
  1037. }
  1038. pmIedName := ""
  1039. mmIedName := ""
  1040. pl_iedname := tools.IsEmpty(row["ied_name"])
  1041. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1042. //添加间隔数据
  1043. dbdata := T_data_check_area{
  1044. ModelId: modelid,
  1045. ScdId: c.ScdId,
  1046. AreaType: "L",
  1047. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  1048. }
  1049. newid, err := db.Insert(&dbdata)
  1050. if err != nil {
  1051. logger.Logger.Error(err)
  1052. return
  1053. }
  1054. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1055. insvalues := []string{}
  1056. for _, ty := range strings.Split(iedtypes, ",") {
  1057. inAreaIedName := ""
  1058. if ty == "PM" {
  1059. //母线保护和母线合并单元装置编号跟随变压器
  1060. //查找变压器编号
  1061. //1号变压器->2号变压器->3号
  1062. inAreaIedName = c.getPMName(iednameParts, ieds)
  1063. pmIedName = inAreaIedName
  1064. if mmIedName == "" {
  1065. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1066. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1067. //使用PM装置的名称去定义MM的名称
  1068. ty = "MM"
  1069. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1070. mmIedName = inAreaIedName
  1071. }
  1072. } else if ty == "MM" {
  1073. if pmIedName != "" && mmIedName == "" {
  1074. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1075. //使用PM装置的名称去定义MM的名称
  1076. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1077. mmIedName = inAreaIedName
  1078. } else {
  1079. continue
  1080. }
  1081. } else {
  1082. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1083. }
  1084. if strings.Index("ABCDE", iednameParts[7]) > -1 {
  1085. //最后一位是字母则说明是AB套
  1086. switch ty {
  1087. case "CL":
  1088. //测控装置,先判断是否分了AB套,没有标识(ied名称的最后一位是否是字母)则说明是多套共用装置
  1089. clIedname := inAreaIedName + iednameParts[7]
  1090. iedObj := ieds[inAreaIedName]
  1091. if iedObj != nil {
  1092. //当前测控装置也分了AB套
  1093. inAreaIedName = clIedname
  1094. }
  1095. break
  1096. default:
  1097. break
  1098. }
  1099. }
  1100. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1101. }
  1102. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1103. if err != nil {
  1104. logger.Logger.Error(err)
  1105. return
  1106. }
  1107. //如果mm装置还未确定
  1108. if mmIedName == "" {
  1109. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1110. inAreaIedName := c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1111. _, err = db.Raw(ins1 + fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M")).Exec()
  1112. if err != nil {
  1113. logger.Logger.Error(err)
  1114. return
  1115. }
  1116. }
  1117. }
  1118. }
  1119. //母联间隔分析
  1120. func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm.Params, pjIed string) {
  1121. scdParseMgr := new(ScdParse)
  1122. //scdNodeMgr := new(ScdNode)
  1123. db := orm.NewOrm()
  1124. //scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1125. for _, row := range ieds {
  1126. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != pjIed[1:2] {
  1127. continue
  1128. }
  1129. pmIedName := ""
  1130. mmIedName := ""
  1131. pl_iedname := tools.IsEmpty(row["ied_name"])
  1132. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1133. //添加间隔数据
  1134. dbdata := T_data_check_area{
  1135. ModelId: modelid,
  1136. ScdId: c.ScdId,
  1137. AreaType: "J",
  1138. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  1139. }
  1140. newid, err := db.Insert(&dbdata)
  1141. if err != nil {
  1142. logger.Logger.Error(err)
  1143. return
  1144. }
  1145. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1146. insvalues := []string{}
  1147. for _, ty := range strings.Split(iedtypes, ",") {
  1148. inAreaIedName := ""
  1149. if ty == "PM" {
  1150. //母线保护和母线合并单元装置编号跟随变压器
  1151. //查找变压器编号
  1152. //1号变压器->2号变压器->3号
  1153. inAreaIedName = c.getPMName(iednameParts, ieds)
  1154. pmIedName = inAreaIedName
  1155. if mmIedName == "" {
  1156. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1157. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1158. //使用PM装置的名称去定义MM的名称
  1159. ty = "MM"
  1160. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1161. mmIedName = inAreaIedName
  1162. }
  1163. } else if ty == "MM" {
  1164. if pmIedName != "" && mmIedName == "" {
  1165. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1166. //使用PM装置的名称去定义MM的名称
  1167. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1168. mmIedName = inAreaIedName
  1169. } else {
  1170. continue
  1171. }
  1172. } else {
  1173. ty = ty[0:1] + pjIed[1:2]
  1174. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1175. //判断与基准保护装置相同套号的装置是否存在
  1176. if ieds[inAreaIedName] == nil {
  1177. //尝试去除套号
  1178. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1179. }
  1180. }
  1181. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1182. }
  1183. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1184. if err != nil {
  1185. logger.Logger.Error(err)
  1186. return
  1187. }
  1188. }
  1189. }
  1190. //母联间隔装置关系检查
  1191. func (c *CheckAreaMgr) cJ(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNodeRule *ScdNodeRule, area_name string, ied_refs []orm.Params, area_ieds []orm.Params, pjIed, area_ruleid string) {
  1192. masterIed := new(node_attr.NIED)
  1193. findIedName := ""
  1194. for _, row2 := range area_ieds {
  1195. findIedName = tools.IsEmpty(row2["ied_name"])
  1196. if strings.HasPrefix(findIedName, pjIed) {
  1197. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1198. break
  1199. }
  1200. }
  1201. if masterIed == nil {
  1202. return
  1203. }
  1204. dealFromIed := map[string]int{}
  1205. for _, row := range ied_refs {
  1206. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1207. toiedtype := tools.IsEmpty(row["to_ied_code"])
  1208. reftype := tools.IsEmpty(row["in_type"])
  1209. tmpFromAreaIeds := []orm.Params{}
  1210. tmpToAreaIeds := []orm.Params{}
  1211. for _, row2 := range area_ieds {
  1212. findIedName = tools.IsEmpty(row2["ied_name"])
  1213. if strings.HasPrefix(findIedName, fromiedtype) {
  1214. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1215. if masterIed != nil {
  1216. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1217. } else {
  1218. if dealFromIed[findIedName] == 0 {
  1219. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1220. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1221. //检查未通过
  1222. scdNodeRule.AppendFcdaCheckResult(r)
  1223. }
  1224. dealFromIed[findIedName] = 1
  1225. }
  1226. }
  1227. if strings.HasPrefix(findIedName, toiedtype) {
  1228. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1229. }
  1230. }
  1231. if len(tmpFromAreaIeds) == 0 {
  1232. continue
  1233. }
  1234. if len(tmpToAreaIeds) == 0 {
  1235. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  1236. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1237. //检查未通过
  1238. scdNodeRule.AppendFcdaCheckResult(r)
  1239. continue
  1240. }
  1241. toIedname := ""
  1242. for _, row2 := range tmpFromAreaIeds {
  1243. findIedName = tools.IsEmpty(row2["ied_name"])
  1244. hasToIedRef := false
  1245. hasToIed := false
  1246. for _, row3 := range tmpToAreaIeds {
  1247. toIedname = tools.IsEmpty(row3["ied_name"])
  1248. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  1249. if masterIed != nil {
  1250. hasToIed = true
  1251. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1252. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1253. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1254. if inout != nil {
  1255. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1256. for _, ieditem := range outiedlist {
  1257. outiedname := ieditem["ref_ied_name"].(string)
  1258. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1259. hasToIedRef = true
  1260. break
  1261. }
  1262. }
  1263. }
  1264. if !hasToIedRef {
  1265. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1266. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1267. //检查未通过
  1268. scdNodeRule.AppendFcdaCheckResult(r)
  1269. }
  1270. }
  1271. }
  1272. if !hasToIed {
  1273. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1274. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1275. //检查未通过
  1276. scdNodeRule.AppendFcdaCheckResult(r)
  1277. }
  1278. }
  1279. }
  1280. }
  1281. //线路间隔装置关系检查
  1282. func (c *CheckAreaMgr) cL(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNodeRule *ScdNodeRule, area_name string, ied_refs []orm.Params, area_ieds []orm.Params, area_ruleid string) {
  1283. masterIed := new(node_attr.NIED)
  1284. findIedName := ""
  1285. for _, row2 := range area_ieds {
  1286. findIedName = tools.IsEmpty(row2["ied_name"])
  1287. if strings.HasPrefix(findIedName, "PL") {
  1288. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1289. break
  1290. }
  1291. }
  1292. if masterIed == nil {
  1293. return
  1294. }
  1295. dealFromIed := map[string]int{}
  1296. for _, row := range ied_refs {
  1297. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1298. toiedtype := tools.IsEmpty(row["to_ied_code"])
  1299. reftype := tools.IsEmpty(row["in_type"])
  1300. tmpFromAreaIeds := []orm.Params{}
  1301. tmpToAreaIeds := []orm.Params{}
  1302. for _, row2 := range area_ieds {
  1303. findIedName = tools.IsEmpty(row2["ied_name"])
  1304. if strings.HasPrefix(findIedName, fromiedtype) {
  1305. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1306. if masterIed != nil {
  1307. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1308. } else {
  1309. if dealFromIed[findIedName] == 0 {
  1310. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1311. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1312. //检查未通过
  1313. scdNodeRule.AppendFcdaCheckResult(r)
  1314. }
  1315. dealFromIed[findIedName] = 1
  1316. }
  1317. }
  1318. if strings.HasPrefix(findIedName, toiedtype) {
  1319. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1320. }
  1321. }
  1322. if len(tmpFromAreaIeds) == 0 {
  1323. continue
  1324. }
  1325. if len(tmpToAreaIeds) == 0 {
  1326. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  1327. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1328. //检查未通过
  1329. scdNodeRule.AppendFcdaCheckResult(r)
  1330. continue
  1331. }
  1332. toIedname := ""
  1333. for _, row2 := range tmpFromAreaIeds {
  1334. findIedName = tools.IsEmpty(row2["ied_name"])
  1335. hasToIedRef := false
  1336. hasToIed := false
  1337. for _, row3 := range tmpToAreaIeds {
  1338. toIedname = tools.IsEmpty(row3["ied_name"])
  1339. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  1340. if masterIed != nil {
  1341. hasToIed = true
  1342. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1343. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1344. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1345. if inout != nil {
  1346. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1347. for _, ieditem := range outiedlist {
  1348. outiedname := ieditem["ref_ied_name"].(string)
  1349. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1350. hasToIedRef = true
  1351. break
  1352. }
  1353. }
  1354. }
  1355. if !hasToIedRef {
  1356. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1357. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1358. //检查未通过
  1359. scdNodeRule.AppendFcdaCheckResult(r)
  1360. }
  1361. }
  1362. }
  1363. if !hasToIed {
  1364. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1365. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1366. //检查未通过
  1367. scdNodeRule.AppendFcdaCheckResult(r)
  1368. }
  1369. }
  1370. }
  1371. }
  1372. //变压器间隔装置关系检查
  1373. func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNodeRule *ScdNodeRule, area_name string, ied_refs []orm.Params, area_ieds []orm.Params, area_ruleid string, HasAreaJ bool) {
  1374. masterIed := new(node_attr.NIED)
  1375. findIedName := ""
  1376. for _, row2 := range area_ieds {
  1377. findIedName = tools.IsEmpty(row2["ied_name"])
  1378. if strings.HasPrefix(findIedName, "PT") {
  1379. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1380. break
  1381. }
  1382. }
  1383. if masterIed == nil {
  1384. return
  1385. }
  1386. scdParseMgr := new(ScdParse)
  1387. dealFromIed := map[string]int{}
  1388. for _, row := range ied_refs {
  1389. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1390. fromiedtype = strings.Split(fromiedtype, "#")[0] //去除后面的电压级别标识
  1391. toiedtype := strings.Split(tools.IsEmpty(row["to_ied_code"]), "#")[0] //去除后面的电压级别标识
  1392. reftype := tools.IsEmpty(row["in_type"])
  1393. tmpFromAreaIeds := []orm.Params{}
  1394. tmpToAreaIeds := []orm.Params{}
  1395. for _, row2 := range area_ieds {
  1396. findIedName = tools.IsEmpty(row2["ied_name"])
  1397. if strings.HasPrefix(findIedName, fromiedtype) {
  1398. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1399. if masterIed != nil {
  1400. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1401. } else {
  1402. if dealFromIed[findIedName] == 0 {
  1403. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1404. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1405. //检查未通过
  1406. scdNodeRule.AppendFcdaCheckResult(r)
  1407. }
  1408. dealFromIed[findIedName] = 1
  1409. }
  1410. }
  1411. if strings.HasPrefix(findIedName, toiedtype) {
  1412. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1413. }
  1414. }
  1415. if len(tmpFromAreaIeds) == 0 {
  1416. continue
  1417. }
  1418. if len(tmpToAreaIeds) == 0 {
  1419. logger.Logger.Debug(fmt.Sprintf("缺失类型关联装置 :%+v", row))
  1420. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的%s信号装置", area_name, toiedtype, reftype)
  1421. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1422. //检查未通过
  1423. scdNodeRule.AppendFcdaCheckResult(r)
  1424. continue
  1425. }
  1426. toIedname := ""
  1427. for _, row2 := range tmpFromAreaIeds {
  1428. findIedName = tools.IsEmpty(row2["ied_name"])
  1429. hasToIedRef := false
  1430. hasToIed := false
  1431. t1 := fromiedtype + "->" + toiedtype
  1432. volLevel := "" //电压等级
  1433. if t1 == "CT->IT" || t1 == "IT->CT" || t1 == "CT->IB" || t1 == "IB->CT" || t1 == "MM->MT" || t1 == "PM->IB" || t1 == "IB->PM" || t1 == "PM->IT" || t1 == "IT->PM" {
  1434. ps := scdParseMgr.ParseIedName(findIedName)
  1435. volLevel = ps[3] + ps[4]
  1436. }
  1437. hasSameVolIed := false
  1438. for _, row3 := range tmpToAreaIeds {
  1439. toIedname = tools.IsEmpty(row3["ied_name"])
  1440. if volLevel != "" {
  1441. ps := scdParseMgr.ParseIedName(toIedname)
  1442. if volLevel != ps[3]+ps[4] {
  1443. //排除不是同一电压等级的装置
  1444. continue
  1445. }
  1446. hasSameVolIed = true
  1447. }
  1448. if scdNodeMgr.GetIed(scdXmlObj, "", toIedname) != nil {
  1449. hasToIed = true
  1450. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1451. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1452. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1453. if inout != nil {
  1454. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1455. for _, ieditem := range outiedlist {
  1456. outiedname := ieditem["ref_ied_name"].(string)
  1457. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1458. hasToIedRef = true
  1459. break
  1460. }
  1461. }
  1462. }
  1463. if !hasToIedRef {
  1464. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1465. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1466. //检查未通过
  1467. scdNodeRule.AppendFcdaCheckResult(r)
  1468. }
  1469. }
  1470. if hasSameVolIed {
  1471. break
  1472. }
  1473. }
  1474. if toiedtype != "PT" {
  1475. if volLevel != "" && !hasSameVolIed {
  1476. parse_result := fmt.Sprintf("间隔%s的装置%s缺失同电压等级的关联类型%s装置", area_name, findIedName, toiedtype)
  1477. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1478. //检查未通过
  1479. scdNodeRule.AppendFcdaCheckResult(r)
  1480. } else if !hasToIed {
  1481. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1482. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1483. //检查未通过
  1484. scdNodeRule.AppendFcdaCheckResult(r)
  1485. }
  1486. }
  1487. }
  1488. }
  1489. }
  1490. //根据参考ied name找出应该关联PM装置
  1491. func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params) string {
  1492. tmpIedName := "PM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + "1" + iednameParts[7]
  1493. iedObj := ieds[tmpIedName]
  1494. if iedObj != nil {
  1495. } else {
  1496. tmpIedName = "PM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + "2" + iednameParts[7]
  1497. iedObj = ieds[tmpIedName]
  1498. if iedObj != nil {
  1499. return tmpIedName
  1500. }
  1501. }
  1502. return tmpIedName
  1503. }
  1504. //根据参考ied name找出应该关联MM装置
  1505. func (c *CheckAreaMgr) getMMName(iednameParts []string, ieds map[string]orm.Params, ab string) string {
  1506. tmpIedName := "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + ab
  1507. if ieds[tmpIedName] == nil {
  1508. tmpIedName = "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1509. }
  1510. return tmpIedName
  1511. }
  1512. //根据当前设备列表,分析出电压等级(高、中、低)的设备列表
  1513. // CT测控、IT智能终端、MT合并单元需要判断是否是本体装置,是则将其归为主变高压侧
  1514. func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string) (hightLst, middleLst, lowLst []orm.Params) {
  1515. tmpLst := map[string][]orm.Params{}
  1516. for _, v := range vollevel {
  1517. tmpLst[v] = []orm.Params{}
  1518. }
  1519. scdParseMgr := new(ScdParse)
  1520. for _, row := range ieds {
  1521. pl_iedname := tools.IsEmpty(row["ied_name"])
  1522. if pl_iedname[0:len(iedtype)] != iedtype {
  1523. continue
  1524. }
  1525. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1526. volvalue := iednameParts[3] + iednameParts[4]
  1527. if tmpLst[volvalue] == nil {
  1528. tmpLst[volvalue] = []orm.Params{row}
  1529. } else {
  1530. tmpLst[volvalue] = append(tmpLst[volvalue], row)
  1531. }
  1532. }
  1533. return tmpLst[vollevel["hight"]], tmpLst[vollevel["middle"]], tmpLst[vollevel["low"]]
  1534. }
  1535. func (c *CheckAreaMgr) GetCheckResult(scdid int64) ([]orm.Params, error) {
  1536. db := orm.NewOrm()
  1537. rowset := []orm.Params{}
  1538. sql := "select *,case error_type when 1 then '多余' when 2 then '错误' when 3 then '缺失' else '其他' end error_type_desc from t_scd_fcda_check_result where scd_id=? order by ied_name"
  1539. _, err := db.Raw(sql, scdid).Values(&rowset)
  1540. return rowset, err
  1541. }