checktools_area.go 69 KB

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