checktools_area.go 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  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 == "" || (volLevelCode != "H" && volLevelCode != "M" && volLevelCode != "L") {
  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. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  614. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  615. outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
  616. //检查是否有错误和缺失的端子
  617. hasYaoXinFunc := false //是否具备遥信功能
  618. for _, r := range refrow {
  619. //判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
  620. //遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致,以及是否有缺失和多余的遥信端子
  621. if strings.Contains(tools.IsEmpty(r["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r["from_func_name"]), "遥信") {
  622. hasYaoXinFunc = true
  623. }
  624. extref_name := tools.IsEmpty(r["to_fcda_name"])
  625. fcda_name := tools.IsEmpty(r["from_fcda_name"])
  626. extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
  627. fcda_name_exp := tools.IsEmpty(r["from_fcda_match_exp"])
  628. funcExist := false //设计的功能是否存在
  629. extrefObj := new(node_attr.NExtRef)
  630. for desc, item := range extreflist {
  631. rex, err := regexp.Compile(extref_name_exp)
  632. if err != nil {
  633. logger.Logger.Error(err, "无效的正则表达式:"+extref_name_exp)
  634. return err
  635. }
  636. if rex.MatchString(desc) {
  637. funcExist = true
  638. extrefObj = item
  639. break
  640. }
  641. }
  642. if !funcExist {
  643. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  644. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  645. parse_result := ""
  646. if !funcExist {
  647. parse_result = fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, iedname, extref_name)
  648. }
  649. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  650. "ied_name": iedname,
  651. "ied_desc": iedObj.Desc,
  652. "out_ied_name": outiedname,
  653. "out_ied_desc": outIedObj.Desc,
  654. "fcda_desc": extref_name,
  655. "fcda_addr": "",
  656. "out_fcda_desc": fcda_name,
  657. "out_fcda_addr": "",
  658. "error_type": "3",
  659. }
  660. //检查未通过
  661. scdNodeRule.AppendFcdaCheckResult(re)
  662. } else {
  663. //检查端子是否关联正确
  664. fcda2Exist := false
  665. fcdaObj := new(node_attr.NFCDA)
  666. for desc, item := range outiedFcdaList {
  667. rex, err := regexp.Compile(fcda_name_exp)
  668. if err != nil {
  669. logger.Logger.Error(err, "无效的正则表达式:"+fcda_name_exp)
  670. return err
  671. }
  672. if rex.MatchString(desc) {
  673. fcda2Exist = true
  674. fcdaObj = item
  675. break
  676. }
  677. }
  678. if fcda2Exist && (extrefObj.LdInst != fcdaObj.LdInst ||
  679. extrefObj.LnInst != fcdaObj.LnInst ||
  680. extrefObj.LnClass != fcdaObj.LnClass ||
  681. extrefObj.Prefix != fcdaObj.Prefix ||
  682. extrefObj.DoName != fcdaObj.DoName) {
  683. //不正确
  684. iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
  685. outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
  686. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误", area_name, iedname, extref_name, outiedname, fcda_name)
  687. daname := ""
  688. if fcdaObj.DaName != "" {
  689. daname = "." + fcdaObj.DaName
  690. }
  691. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  692. "ied_name": iedname,
  693. "ied_desc": iedObj.Desc,
  694. "out_ied_name": outiedname,
  695. "out_ied_desc": outIedObj.Desc,
  696. "fcda_desc": extref_name,
  697. "fcda_addr": extrefObj.IntAddr,
  698. "out_fcda_desc": fcda_name,
  699. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", fcdaObj.LdInst, fcdaObj.Prefix, fcdaObj.LnClass, fcdaObj.LnInst, fcdaObj.DoName, daname),
  700. "error_type": "2",
  701. }
  702. //检查未通过
  703. scdNodeRule.AppendFcdaCheckResult(re)
  704. }
  705. }
  706. }
  707. //检查是否有多余(SCD中有不存在于设计中)的端子
  708. for extrefdesc, r := range extreflist { //scd中的端子关系
  709. extref_name := ""
  710. fcda_name := ""
  711. isHave := false
  712. for _, r1 := range refrow { //设计的端子关系
  713. if strings.Contains(tools.IsEmpty(r1["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r1["from_func_name"]), "遥信") {
  714. hasYaoXinFunc = true
  715. }
  716. extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
  717. rex, err := regexp.Compile(extref_name_exp)
  718. if err != nil {
  719. logger.Logger.Error(err)
  720. return err
  721. }
  722. if rex.MatchString(extrefdesc) {
  723. //端子存在
  724. isHave = true
  725. break
  726. }
  727. }
  728. if !isHave {
  729. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s在设计中不存在", area_name, iedname, extref_name)
  730. daname := ""
  731. if r.DaName != "" {
  732. daname = "." + r.DaName
  733. }
  734. doi := scdNodeRule.IedIntAddrExist(iedname, r.IntAddr)
  735. if doi != nil {
  736. extref_name = doi.(*node_attr.NDOI).Desc
  737. }
  738. doi, _ = scdNodeRule.IedFcdaExist(outiedname, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
  739. if doi != nil {
  740. fcda_name = doi.(*node_attr.NDOI).Desc
  741. }
  742. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  743. "ied_name": iedname,
  744. "ied_desc": iedObj.Desc,
  745. "out_ied_name": outiedname,
  746. "out_ied_desc": outIedObj.Desc,
  747. "fcda_desc": extref_name,
  748. "fcda_addr": r.IntAddr,
  749. "out_fcda_desc": fcda_name,
  750. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName, daname),
  751. "error_type": "1",
  752. }
  753. //检查未通过
  754. scdNodeRule.AppendFcdaCheckResult(re)
  755. }
  756. }
  757. if hasYaoXinFunc {
  758. //遥信端子检查:仅根据scd实际配置检查其双方端子的doi名称是否相同
  759. scdMgr := new(ScdMgr)
  760. yx := scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
  761. if len(yx) > 0 {
  762. for extref, doiDesc := range yx {
  763. if extref.IedName != outiedname {
  764. //非当前输入装置的,不处理
  765. continue
  766. }
  767. daname := ""
  768. if extref.DaName != "" {
  769. daname = "." + extref.DaName
  770. }
  771. //获取输出端端子名称
  772. outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
  773. if outFcdaDoi == nil {
  774. //端子缺失
  775. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s的关联端子不存在", area_name, iedname, doiDesc)
  776. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  777. "ied_name": iedname,
  778. "ied_desc": iedObj.Desc,
  779. "out_ied_name": outiedname,
  780. "out_ied_desc": outIedObj.Desc,
  781. "fcda_desc": doiDesc,
  782. "fcda_addr": extref.IntAddr,
  783. "out_fcda_desc": "",
  784. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  785. "error_type": "3",
  786. }
  787. //检查未通过
  788. scdNodeRule.AppendFcdaCheckResult(re)
  789. } else if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
  790. //关联错误
  791. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, outiedname, outFcdaDoi.(*node_attr.NDOI).Desc)
  792. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  793. "ied_name": iedname,
  794. "ied_desc": iedObj.Desc,
  795. "out_ied_name": outiedname,
  796. "out_ied_desc": outIedObj.Desc,
  797. "fcda_desc": doiDesc,
  798. "fcda_addr": extref.IntAddr,
  799. "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
  800. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  801. "error_type": "2",
  802. }
  803. //检查未通过
  804. scdNodeRule.AppendFcdaCheckResult(re)
  805. }
  806. }
  807. }
  808. }
  809. }
  810. }
  811. }
  812. }
  813. scdNodeRule.CheckFinish()
  814. scdNodeRule.Flush()
  815. return nil
  816. }
  817. //解析模型间隔。根据模型定义解析出间隔中的装置
  818. func (c *CheckAreaMgr) ParseModelArea() {
  819. c.Init(c.ScdId)
  820. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  821. areaCheckInfo.Delete(key)
  822. // 取得当前scd所有ied及名称解析结果
  823. dbo := orm.NewOrm()
  824. 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"
  825. iedlst := []orm.Params{}
  826. _, err := dbo.Raw(sql, c.ScdId).Values(&iedlst)
  827. if err != nil {
  828. logger.Logger.Error(err)
  829. return
  830. }
  831. logger.Logger.Debug(fmt.Sprintf("=====总装置数:%d", len(iedlst)))
  832. iedMap := map[string]orm.Params{}
  833. for _, r := range iedlst {
  834. iedMap[tools.IsEmpty(r["ied_name"])] = r
  835. }
  836. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  837. HasAreaJ := false
  838. for _, row := range c.CheckModelList {
  839. areaCode := tools.IsEmpty(row["area_type_code"])
  840. if areaCode == "J" {
  841. HasAreaJ = true
  842. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  843. //modelname := tools.IsEmpty(row["model_name"])
  844. iedtypes := tools.IsEmpty(row["ied_types"])
  845. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  846. c.pJ(modelid, volcode, iedtypes, iedMap, "PE")
  847. c.pJ(modelid, volcode, iedtypes, iedMap, "PJ")
  848. c.pJ(modelid, volcode, iedtypes, iedMap, "PK")
  849. c.pJ(modelid, volcode, iedtypes, iedMap, "PF")
  850. }
  851. }
  852. for _, row := range c.CheckModelList {
  853. //逐一分析模型定义
  854. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  855. modelname := tools.IsEmpty(row["model_name"])
  856. iedtypes := tools.IsEmpty(row["ied_types"])
  857. //模型对应的间隔代码
  858. /*
  859. S 站用变压器
  860. C 电容器
  861. B 断路器
  862. K 母分
  863. J 母联
  864. M 母线
  865. X 电抗器
  866. L 线路
  867. T 主变压器
  868. */
  869. areaCode := tools.IsEmpty(row["area_type_code"])
  870. //模型对应的电压等级
  871. //10:10KV 35:35KV 66:66KV 11:110KV 22:220KV 50:500KV 75:750KV 33:330KV T0:1000KV
  872. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  873. if modelname == "" || iedtypes == "" {
  874. continue
  875. }
  876. //母联间隔已经提前分析,如果没有母联间隔时,主变间隔中不包含母联终端装置
  877. if areaCode == "J" {
  878. continue
  879. }
  880. //获取模型内中装备关系定义
  881. //主变间隔分析:需要查站内该电压等级下的高中低压侧装置或者高低压装置组成一个间隔,以主变保护装置(PT)为起始
  882. if areaCode == "T" {
  883. c.pT(modelid, iedtypes, iedMap, HasAreaJ)
  884. }
  885. //线路保护间隔分析:以线路保护测控装置(PL)为开始分析
  886. if areaCode == "L" {
  887. c.pL(modelid, volcode, iedtypes, iedMap)
  888. }
  889. }
  890. }
  891. //变压器间隔分析
  892. func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Params, HasAreaJ bool) {
  893. scdParseMgr := new(ScdParse)
  894. db := orm.NewOrm()
  895. //获取当前站的各电压等级
  896. volRows := []orm.Params{}
  897. _, 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)
  898. if err != nil {
  899. logger.Logger.Error(err)
  900. return
  901. }
  902. if len(volRows) == 0 {
  903. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  904. return
  905. }
  906. volMap := map[string]string{}
  907. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  908. if len(volRows) == 2 {
  909. volMap["middle"] = ""
  910. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  911. } else {
  912. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  913. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  914. }
  915. var getIedByDesc = func(iedinfo map[string]orm.Params, desc string) (string, string) {
  916. scdParseMgr := new(ScdParse)
  917. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  918. for vn, row := range iedinfo {
  919. v := tools.IsEmpty(row["ied_desc"])
  920. if v == "" {
  921. if scdXmlObj == nil {
  922. return "", ""
  923. }
  924. scdNode := new(ScdNode)
  925. ied := scdNode.GetIed(scdXmlObj, "", vn)
  926. if ied == nil {
  927. return "", ""
  928. }
  929. v = ied.Desc
  930. }
  931. if strings.Contains(v, desc) {
  932. return v, vn
  933. }
  934. }
  935. return "", ""
  936. }
  937. //判断是否将各电压等级的保护装置合并还是分开的间隔
  938. //如果存在高中低压的保护装置,则说明是分开的主变间隔
  939. //isMarge := true // 默认为合并的主变间隔
  940. for _, row := range ieds {
  941. if tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "T" {
  942. continue
  943. }
  944. //判断主变保护是否是按电压等级分开配置的模型
  945. /*
  946. if strings.Contains(iedtypes, "PT#H") || strings.Contains(iedtypes, "PT#M") || strings.Contains(iedtypes, "PT#L") {
  947. h, m, l := c.getIedListByVol("PT", ieds, volMap)
  948. } else {
  949. pl_iedname := tools.IsEmpty(row["ied_name"])
  950. }
  951. */
  952. //pmIedName := ""
  953. //mmIedName := ""
  954. pl_iedname := tools.IsEmpty(row["ied_name"])
  955. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  956. //添加间隔数据
  957. dbdata := T_data_check_area{
  958. ModelId: modelid,
  959. ScdId: c.ScdId,
  960. AreaType: "T",
  961. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  962. }
  963. newid, err := db.Insert(&dbdata)
  964. if err != nil {
  965. logger.Logger.Error(err)
  966. return
  967. }
  968. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  969. insvalues := []string{}
  970. inAreaIedName := pl_iedname
  971. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "T"))
  972. //判断间隔是否需要包含差动装置
  973. if strings.Contains(iedtypes, "PT#C") {
  974. ieddesc, iedname := getIedByDesc(ieds, "差动")
  975. if strings.Contains(ieddesc, "差动") {
  976. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, iedname, "P", "TC"))
  977. }
  978. }
  979. //判断间隔是否需要包含本体保护装置
  980. if strings.Contains(iedtypes, "PT#0") {
  981. ieddesc, iedname := getIedByDesc(ieds, "本体")
  982. if strings.Contains(ieddesc, "本体") {
  983. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, iedname, "P", "T0"))
  984. }
  985. }
  986. //合智一体IMT/MIT,分高中低压
  987. h, m, l := c.getIedListByVol("IMT", ieds, volMap)
  988. h = append(h, m...)
  989. h = append(h, l...)
  990. for _, r := range h {
  991. inAreaIedName = tools.IsEmpty(r["ied_name"])
  992. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  993. lastChar := tmpIednameParts[7]
  994. if lastChar == iednameParts[7] {
  995. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "IM", "T"))
  996. }
  997. }
  998. h, m, l = c.getIedListByVol("MIT", ieds, volMap)
  999. h = append(h, m...)
  1000. h = append(h, l...)
  1001. for _, r := range h {
  1002. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1003. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1004. lastChar := tmpIednameParts[7]
  1005. if lastChar == iednameParts[7] {
  1006. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "MI", "T"))
  1007. }
  1008. }
  1009. //母联智能终端IE需要分高中压,无低压侧
  1010. if HasAreaJ {
  1011. h, m, l = c.getIedListByVol("IE", ieds, volMap)
  1012. for _, r := range h {
  1013. //高压侧,AB套必须与PT装置相同
  1014. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1015. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1016. lastChar := tmpIednameParts[7]
  1017. if lastChar == iednameParts[7] {
  1018. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "E"))
  1019. }
  1020. }
  1021. for _, r := range m {
  1022. //中压侧
  1023. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1024. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1025. lastChar := tmpIednameParts[7]
  1026. if lastChar == "" || lastChar == iednameParts[7] {
  1027. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "E"))
  1028. }
  1029. }
  1030. }
  1031. //合并单元MT分高中低压侧;低压侧无关联母线合并单元MM
  1032. h, m, l = c.getIedListByVol("MT", ieds, volMap)
  1033. h = append(h, m...)
  1034. h = append(h, l...)
  1035. for _, r := range h {
  1036. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1037. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1038. lastChar := tmpIednameParts[7]
  1039. if lastChar == iednameParts[7] {
  1040. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "T"))
  1041. }
  1042. }
  1043. //测控装置CT分高中低压侧,且可能是多套合并单元MT共用,既不分AB套
  1044. h, m, l = c.getIedListByVol("CT", ieds, volMap)
  1045. h = append(h, m...)
  1046. h = append(h, l...)
  1047. for _, r := range h {
  1048. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1049. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1050. lastChar := tmpIednameParts[7]
  1051. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  1052. //高中低压电压等级相同的
  1053. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  1054. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "C", "T"))
  1055. }
  1056. }
  1057. //智能终端(IB:开关\IT:分支\IF:分段)分高中低压侧
  1058. h, m, l = c.getIedListByVol("IB", ieds, volMap)
  1059. h = append(h, m...)
  1060. h = append(h, l...)
  1061. for _, r := range h {
  1062. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1063. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1064. lastChar := tmpIednameParts[7]
  1065. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  1066. //高中低压电压等级相同的
  1067. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  1068. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "B"))
  1069. }
  1070. }
  1071. h, m, l = c.getIedListByVol("IT", ieds, volMap)
  1072. h = append(h, m...)
  1073. h = append(h, l...)
  1074. for _, r := range h {
  1075. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1076. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1077. lastChar := tmpIednameParts[7]
  1078. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  1079. //高中低压电压等级相同的
  1080. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  1081. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "T"))
  1082. }
  1083. }
  1084. h, m, l = c.getIedListByVol("IF", ieds, volMap)
  1085. h = append(h, m...)
  1086. h = append(h, l...)
  1087. for _, r := range h {
  1088. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1089. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1090. lastChar := tmpIednameParts[7]
  1091. tmpVol := tmpIednameParts[3] + tmpIednameParts[4]
  1092. //高中低压电压等级相同的
  1093. if (tmpVol == volMap["low"] || tmpVol == volMap["middle"] || tmpVol == volMap["hight"]) && (lastChar == "" || lastChar == iednameParts[7]) {
  1094. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "I", "F"))
  1095. }
  1096. }
  1097. //母线保护PM及母线合并单元MM,可能是多套合并单元MT共用,既不分AB套;低压侧智能终端无关联母线保护
  1098. h, m, l = c.getIedListByVol("PM", ieds, volMap)
  1099. for _, r := range h {
  1100. //高压侧,AB套必须与PT装置相同
  1101. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1102. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1103. lastChar := tmpIednameParts[7]
  1104. if lastChar == iednameParts[7] {
  1105. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1106. //MM装置
  1107. mmIedName := c.getMMName(tmpIednameParts, ieds, iednameParts[7])
  1108. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, mmIedName, "M", "M"))
  1109. break
  1110. }
  1111. }
  1112. for _, r := range m {
  1113. //中压侧
  1114. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1115. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1116. lastChar := tmpIednameParts[7]
  1117. if lastChar == "" || lastChar == iednameParts[7] {
  1118. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1119. //MM装置
  1120. mmIedName := c.getMMName(tmpIednameParts, ieds, iednameParts[7])
  1121. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, mmIedName, "M", "M"))
  1122. break
  1123. }
  1124. }
  1125. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1126. if err != nil {
  1127. logger.Logger.Error(err)
  1128. return
  1129. }
  1130. }
  1131. }
  1132. //线路间隔分析
  1133. //vol:电压等级
  1134. func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1135. scdParseMgr := new(ScdParse)
  1136. //scdNodeMgr := new(ScdNode)
  1137. db := orm.NewOrm()
  1138. //scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1139. for _, row := range ieds {
  1140. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "L" {
  1141. continue
  1142. }
  1143. pmIedName := ""
  1144. mmIedName := ""
  1145. pl_iedname := tools.IsEmpty(row["ied_name"])
  1146. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1147. //添加间隔数据
  1148. dbdata := T_data_check_area{
  1149. ModelId: modelid,
  1150. ScdId: c.ScdId,
  1151. AreaType: "L",
  1152. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  1153. }
  1154. newid, err := db.Insert(&dbdata)
  1155. if err != nil {
  1156. logger.Logger.Error(err)
  1157. return
  1158. }
  1159. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1160. insvalues := []string{}
  1161. for _, ty := range strings.Split(iedtypes, ",") {
  1162. inAreaIedName := ""
  1163. if ty == "PM" {
  1164. //母线保护和母线合并单元装置编号跟随变压器
  1165. //查找变压器编号
  1166. //1号变压器->2号变压器->3号
  1167. inAreaIedName = c.getPMName(iednameParts, ieds)
  1168. pmIedName = inAreaIedName
  1169. if mmIedName == "" {
  1170. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1171. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1172. //使用PM装置的名称去定义MM的名称
  1173. ty = "MM"
  1174. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1175. mmIedName = inAreaIedName
  1176. }
  1177. } else if ty == "MM" {
  1178. if pmIedName != "" && mmIedName == "" {
  1179. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1180. //使用PM装置的名称去定义MM的名称
  1181. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1182. mmIedName = inAreaIedName
  1183. } else {
  1184. continue
  1185. }
  1186. } else {
  1187. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1188. }
  1189. if strings.Index("ABCDE", iednameParts[7]) > -1 {
  1190. //最后一位是字母则说明是AB套
  1191. switch ty {
  1192. case "CL":
  1193. //测控装置,先判断是否分了AB套,没有标识(ied名称的最后一位是否是字母)则说明是多套共用装置
  1194. clIedname := inAreaIedName + iednameParts[7]
  1195. iedObj := ieds[inAreaIedName]
  1196. if iedObj != nil {
  1197. //当前测控装置也分了AB套
  1198. inAreaIedName = clIedname
  1199. }
  1200. break
  1201. default:
  1202. break
  1203. }
  1204. }
  1205. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1206. }
  1207. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1208. if err != nil {
  1209. logger.Logger.Error(err)
  1210. return
  1211. }
  1212. //如果mm装置还未确定
  1213. if mmIedName == "" {
  1214. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1215. inAreaIedName := c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1216. _, err = db.Raw(ins1 + fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M")).Exec()
  1217. if err != nil {
  1218. logger.Logger.Error(err)
  1219. return
  1220. }
  1221. }
  1222. }
  1223. }
  1224. //母联间隔分析
  1225. func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm.Params, pjIed string) {
  1226. scdParseMgr := new(ScdParse)
  1227. //scdNodeMgr := new(ScdNode)
  1228. db := orm.NewOrm()
  1229. //scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1230. for _, row := range ieds {
  1231. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != pjIed[1:2] {
  1232. continue
  1233. }
  1234. pmIedName := ""
  1235. mmIedName := ""
  1236. pl_iedname := tools.IsEmpty(row["ied_name"])
  1237. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1238. //添加间隔数据
  1239. dbdata := T_data_check_area{
  1240. ModelId: modelid,
  1241. ScdId: c.ScdId,
  1242. AreaType: "J",
  1243. AreaName: tools.IsEmpty(row["area_name"]) + iednameParts[7],
  1244. }
  1245. newid, err := db.Insert(&dbdata)
  1246. if err != nil {
  1247. logger.Logger.Error(err)
  1248. return
  1249. }
  1250. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1251. insvalues := []string{}
  1252. for _, ty := range strings.Split(iedtypes, ",") {
  1253. inAreaIedName := ""
  1254. if ty == "PM" {
  1255. //母线保护和母线合并单元装置编号跟随变压器
  1256. //查找变压器编号
  1257. //1号变压器->2号变压器->3号
  1258. inAreaIedName = c.getPMName(iednameParts, ieds)
  1259. pmIedName = inAreaIedName
  1260. if mmIedName == "" {
  1261. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1262. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1263. //使用PM装置的名称去定义MM的名称
  1264. ty = "MM"
  1265. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1266. mmIedName = inAreaIedName
  1267. }
  1268. } else if ty == "MM" {
  1269. if pmIedName != "" && mmIedName == "" {
  1270. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1271. //使用PM装置的名称去定义MM的名称
  1272. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1273. mmIedName = inAreaIedName
  1274. } else {
  1275. continue
  1276. }
  1277. } else {
  1278. ty = ty[0:1] + pjIed[1:2]
  1279. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1280. //判断与基准保护装置相同套号的装置是否存在
  1281. if ieds[inAreaIedName] == nil {
  1282. //尝试去除套号
  1283. inAreaIedName = ty + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1284. }
  1285. }
  1286. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ty[0:1], ty[1:2]))
  1287. }
  1288. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1289. if err != nil {
  1290. logger.Logger.Error(err)
  1291. return
  1292. }
  1293. }
  1294. }
  1295. //母联间隔装置关系检查
  1296. 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) {
  1297. masterIed := new(node_attr.NIED)
  1298. findIedName := ""
  1299. for _, row2 := range area_ieds {
  1300. findIedName = tools.IsEmpty(row2["ied_name"])
  1301. if strings.HasPrefix(findIedName, pjIed) {
  1302. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1303. break
  1304. }
  1305. }
  1306. if masterIed == nil {
  1307. return
  1308. }
  1309. dealFromIed := map[string]int{}
  1310. for _, row := range ied_refs {
  1311. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1312. toiedtype := tools.IsEmpty(row["to_ied_code"])
  1313. reftype := tools.IsEmpty(row["in_type"])
  1314. tmpFromAreaIeds := []orm.Params{}
  1315. tmpToAreaIeds := []orm.Params{}
  1316. for _, row2 := range area_ieds {
  1317. findIedName = tools.IsEmpty(row2["ied_name"])
  1318. if strings.HasPrefix(findIedName, fromiedtype) {
  1319. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1320. if masterIed != nil {
  1321. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1322. } else {
  1323. if dealFromIed[findIedName] == 0 {
  1324. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1325. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1326. //检查未通过
  1327. scdNodeRule.AppendFcdaCheckResult(r)
  1328. }
  1329. dealFromIed[findIedName] = 1
  1330. }
  1331. }
  1332. if strings.HasPrefix(findIedName, toiedtype) {
  1333. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1334. }
  1335. }
  1336. if len(tmpFromAreaIeds) == 0 {
  1337. continue
  1338. }
  1339. if len(tmpToAreaIeds) == 0 {
  1340. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  1341. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1342. //检查未通过
  1343. scdNodeRule.AppendFcdaCheckResult(r)
  1344. continue
  1345. }
  1346. toIedname := ""
  1347. for _, row2 := range tmpFromAreaIeds {
  1348. findIedName = tools.IsEmpty(row2["ied_name"])
  1349. hasToIedRef := false
  1350. hasToIed := false
  1351. for _, row3 := range tmpToAreaIeds {
  1352. toIedname = tools.IsEmpty(row3["ied_name"])
  1353. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  1354. if masterIed != nil {
  1355. hasToIed = true
  1356. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1357. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1358. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1359. if inout != nil {
  1360. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1361. for _, ieditem := range outiedlist {
  1362. outiedname := ieditem["ref_ied_name"].(string)
  1363. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1364. hasToIedRef = true
  1365. break
  1366. }
  1367. }
  1368. }
  1369. if !hasToIedRef {
  1370. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1371. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1372. //检查未通过
  1373. scdNodeRule.AppendFcdaCheckResult(r)
  1374. }
  1375. }
  1376. }
  1377. if !hasToIed {
  1378. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1379. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1380. //检查未通过
  1381. scdNodeRule.AppendFcdaCheckResult(r)
  1382. }
  1383. }
  1384. }
  1385. }
  1386. //线路间隔装置关系检查
  1387. 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) {
  1388. masterIed := new(node_attr.NIED)
  1389. findIedName := ""
  1390. for _, row2 := range area_ieds {
  1391. findIedName = tools.IsEmpty(row2["ied_name"])
  1392. if strings.HasPrefix(findIedName, "PL") {
  1393. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1394. break
  1395. }
  1396. }
  1397. if masterIed == nil {
  1398. return
  1399. }
  1400. dealFromIed := map[string]int{}
  1401. for _, row := range ied_refs {
  1402. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1403. toiedtype := tools.IsEmpty(row["to_ied_code"])
  1404. reftype := tools.IsEmpty(row["in_type"])
  1405. tmpFromAreaIeds := []orm.Params{}
  1406. tmpToAreaIeds := []orm.Params{}
  1407. for _, row2 := range area_ieds {
  1408. findIedName = tools.IsEmpty(row2["ied_name"])
  1409. if strings.HasPrefix(findIedName, fromiedtype) {
  1410. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1411. if masterIed != nil {
  1412. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1413. } else {
  1414. if dealFromIed[findIedName] == 0 {
  1415. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1416. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1417. //检查未通过
  1418. scdNodeRule.AppendFcdaCheckResult(r)
  1419. }
  1420. dealFromIed[findIedName] = 1
  1421. }
  1422. }
  1423. if strings.HasPrefix(findIedName, toiedtype) {
  1424. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1425. }
  1426. }
  1427. if len(tmpFromAreaIeds) == 0 {
  1428. continue
  1429. }
  1430. if len(tmpToAreaIeds) == 0 {
  1431. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  1432. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1433. //检查未通过
  1434. scdNodeRule.AppendFcdaCheckResult(r)
  1435. continue
  1436. }
  1437. toIedname := ""
  1438. for _, row2 := range tmpFromAreaIeds {
  1439. findIedName = tools.IsEmpty(row2["ied_name"])
  1440. hasToIedRef := false
  1441. hasToIed := false
  1442. for _, row3 := range tmpToAreaIeds {
  1443. toIedname = tools.IsEmpty(row3["ied_name"])
  1444. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  1445. if masterIed != nil {
  1446. hasToIed = true
  1447. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1448. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1449. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1450. if inout != nil {
  1451. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1452. for _, ieditem := range outiedlist {
  1453. outiedname := ieditem["ref_ied_name"].(string)
  1454. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1455. hasToIedRef = true
  1456. break
  1457. }
  1458. }
  1459. }
  1460. if !hasToIedRef {
  1461. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1462. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1463. //检查未通过
  1464. scdNodeRule.AppendFcdaCheckResult(r)
  1465. }
  1466. }
  1467. }
  1468. if !hasToIed {
  1469. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1470. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1471. //检查未通过
  1472. scdNodeRule.AppendFcdaCheckResult(r)
  1473. }
  1474. }
  1475. }
  1476. }
  1477. //变压器间隔装置关系检查
  1478. 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) {
  1479. masterIed := new(node_attr.NIED)
  1480. findIedName := ""
  1481. for _, row2 := range area_ieds {
  1482. findIedName = tools.IsEmpty(row2["ied_name"])
  1483. if strings.HasPrefix(findIedName, "PT") {
  1484. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1485. break
  1486. }
  1487. }
  1488. if masterIed == nil {
  1489. return
  1490. }
  1491. scdParseMgr := new(ScdParse)
  1492. dealFromIed := map[string]int{}
  1493. for _, row := range ied_refs {
  1494. fromiedtype := tools.IsEmpty(row["from_ied_code"])
  1495. fromiedtype = strings.Split(fromiedtype, "#")[0] //去除后面的电压级别标识
  1496. toiedtype := strings.Split(tools.IsEmpty(row["to_ied_code"]), "#")[0] //去除后面的电压级别标识
  1497. reftype := tools.IsEmpty(row["in_type"])
  1498. tmpFromAreaIeds := []orm.Params{}
  1499. tmpToAreaIeds := []orm.Params{}
  1500. for _, row2 := range area_ieds {
  1501. findIedName = tools.IsEmpty(row2["ied_name"])
  1502. if strings.HasPrefix(findIedName, fromiedtype) {
  1503. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1504. if masterIed != nil {
  1505. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  1506. } else {
  1507. if dealFromIed[findIedName] == 0 {
  1508. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  1509. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1510. //检查未通过
  1511. scdNodeRule.AppendFcdaCheckResult(r)
  1512. }
  1513. dealFromIed[findIedName] = 1
  1514. }
  1515. }
  1516. if strings.HasPrefix(findIedName, toiedtype) {
  1517. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  1518. }
  1519. }
  1520. if len(tmpFromAreaIeds) == 0 {
  1521. continue
  1522. }
  1523. if len(tmpToAreaIeds) == 0 {
  1524. logger.Logger.Debug(fmt.Sprintf("缺失类型关联装置 :%+v", row))
  1525. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的%s信号装置", area_name, toiedtype, reftype)
  1526. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1527. //检查未通过
  1528. scdNodeRule.AppendFcdaCheckResult(r)
  1529. continue
  1530. }
  1531. toIedname := ""
  1532. for _, row2 := range tmpFromAreaIeds {
  1533. findIedName = tools.IsEmpty(row2["ied_name"])
  1534. hasToIedRef := false
  1535. hasToIed := false
  1536. t1 := fromiedtype + "->" + toiedtype
  1537. volLevel := "" //电压等级
  1538. 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" {
  1539. ps := scdParseMgr.ParseIedName(findIedName)
  1540. volLevel = ps[3] + ps[4]
  1541. }
  1542. hasSameVolIed := false
  1543. for _, row3 := range tmpToAreaIeds {
  1544. toIedname = tools.IsEmpty(row3["ied_name"])
  1545. if volLevel != "" {
  1546. ps := scdParseMgr.ParseIedName(toIedname)
  1547. if volLevel != ps[3]+ps[4] {
  1548. //排除不是同一电压等级的装置
  1549. continue
  1550. }
  1551. hasSameVolIed = true
  1552. }
  1553. if scdNodeMgr.GetIed(scdXmlObj, "", toIedname) != nil {
  1554. hasToIed = true
  1555. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  1556. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  1557. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  1558. if inout != nil {
  1559. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  1560. for _, ieditem := range outiedlist {
  1561. outiedname := ieditem["ref_ied_name"].(string)
  1562. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  1563. hasToIedRef = true
  1564. break
  1565. }
  1566. }
  1567. }
  1568. if !hasToIedRef {
  1569. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  1570. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1571. //检查未通过
  1572. scdNodeRule.AppendFcdaCheckResult(r)
  1573. }
  1574. }
  1575. if hasSameVolIed {
  1576. break
  1577. }
  1578. }
  1579. if toiedtype != "PT" {
  1580. if volLevel != "" && !hasSameVolIed {
  1581. parse_result := fmt.Sprintf("间隔%s的装置%s缺失同电压等级的关联类型%s装置", area_name, findIedName, toiedtype)
  1582. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1583. //检查未通过
  1584. scdNodeRule.AppendFcdaCheckResult(r)
  1585. } else if !hasToIed {
  1586. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  1587. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  1588. //检查未通过
  1589. scdNodeRule.AppendFcdaCheckResult(r)
  1590. }
  1591. }
  1592. }
  1593. }
  1594. }
  1595. //根据参考ied name找出应该关联PM装置
  1596. func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params) string {
  1597. tmpIedName := "PM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + "1" + iednameParts[7]
  1598. iedObj := ieds[tmpIedName]
  1599. if iedObj != nil {
  1600. } else {
  1601. tmpIedName = "PM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + "2" + iednameParts[7]
  1602. iedObj = ieds[tmpIedName]
  1603. if iedObj != nil {
  1604. return tmpIedName
  1605. }
  1606. }
  1607. return tmpIedName
  1608. }
  1609. //根据参考ied name找出应该关联MM装置
  1610. func (c *CheckAreaMgr) getMMName(iednameParts []string, ieds map[string]orm.Params, ab string) string {
  1611. tmpIedName := "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + ab
  1612. if ieds[tmpIedName] == nil {
  1613. tmpIedName = "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1614. }
  1615. return tmpIedName
  1616. }
  1617. //根据当前设备列表,分析出电压等级(高、中、低)的设备列表
  1618. // CT测控、IT智能终端、MT合并单元需要判断是否是本体装置,是则将其归为主变高压侧
  1619. func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string) (hightLst, middleLst, lowLst []orm.Params) {
  1620. tmpLst := map[string][]orm.Params{}
  1621. for _, v := range vollevel {
  1622. tmpLst[v] = []orm.Params{}
  1623. }
  1624. scdParseMgr := new(ScdParse)
  1625. for _, row := range ieds {
  1626. pl_iedname := tools.IsEmpty(row["ied_name"])
  1627. if pl_iedname[0:len(iedtype)] != iedtype {
  1628. continue
  1629. }
  1630. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1631. volvalue := iednameParts[3] + iednameParts[4]
  1632. if tmpLst[volvalue] == nil {
  1633. tmpLst[volvalue] = []orm.Params{row}
  1634. } else {
  1635. tmpLst[volvalue] = append(tmpLst[volvalue], row)
  1636. }
  1637. }
  1638. return tmpLst[vollevel["hight"]], tmpLst[vollevel["middle"]], tmpLst[vollevel["low"]]
  1639. }
  1640. func (c *CheckAreaMgr) GetCheckResult(scdid int64) ([]orm.Params, error) {
  1641. db := orm.NewOrm()
  1642. rowset := []orm.Params{}
  1643. 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"
  1644. _, err := db.Raw(sql, scdid).Values(&rowset)
  1645. return rowset, err
  1646. }