checktools_area.go 94 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596
  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. IedNo string //所属间隔下支路(线路)在SCD中端子实际编号,如在母线间隔下支路9
  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) Save(model_id int, area_name string) (int, error) {
  129. //判断间隔名称是否重复
  130. db := orm.NewOrm()
  131. rowset := []orm.Params{}
  132. db.Raw("select id from t_data_check_area where scd_id=? and area_name=?", c.ScdId, area_name).Values(&rowset)
  133. if len(rowset) > 0 {
  134. return 0, errors.New("间隔名称" + area_name + "已存在")
  135. }
  136. modelMgr := new(SysCheckModelMgr)
  137. modelMgr.Model.Id = model_id
  138. modelInfo, err := modelMgr.One()
  139. if err != nil {
  140. return 0, err
  141. }
  142. areatype_codeinfo := new(Global).GetCodeInfoByID(tools.IsEmpty(modelInfo.AreaType))
  143. area_type := tools.IsEmpty(areatype_codeinfo["code"])
  144. cr := c.GetUserId()
  145. paras := []interface{}{c.ScdId, area_name, area_type, model_id, cr}
  146. r, err := db.Raw("insert into t_data_check_area(scd_id,area_name,area_type,model_id,cr,voltage_level)values(?,?,?,?,?,0)", paras).Exec()
  147. sqllog := fmt.Sprintf("添加新间隔%s", area_name)
  148. if err != nil {
  149. logger.Logger.Error(err)
  150. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  151. return 0, err
  152. }
  153. new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  154. id, _ := r.LastInsertId()
  155. return int(id), nil
  156. }
  157. //删除指定间隔
  158. func (c *CheckAreaMgr) Del(area_id int) error {
  159. db := orm.NewOrm()
  160. _, err := db.Raw("delete from t_data_check_area where scd_id=? and id=?", c.ScdId, area_id).Exec()
  161. _, err = db.Raw("delete from t_data_check_area_ied where scd_id=? and area_id=?", c.ScdId, area_id).Exec()
  162. sqllog := fmt.Sprintf("删除间隔%d", area_id)
  163. if err != nil {
  164. logger.Logger.Error(err)
  165. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Delete, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  166. } else {
  167. new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Delete, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  168. }
  169. return err
  170. }
  171. //保存指定间隔所属的电压等级
  172. func (c *CheckAreaMgr) SetVoltageLevel(id string, voltagelevel int) error {
  173. db := orm.NewOrm()
  174. _, err := db.Raw("update t_data_check_area set voltage_level=? where id=?", voltagelevel, id).Exec()
  175. return err
  176. }
  177. //修改指定间隔的名称
  178. func (c *CheckAreaMgr) UpdateName(scdid int64, area_id int, name string) error {
  179. db := orm.NewOrm()
  180. areaM := T_data_check_area{Id: int64(area_id), ScdId: scdid}
  181. err := db.Read(&areaM)
  182. if err != nil {
  183. logger.Logger.Error(err)
  184. return err
  185. }
  186. areaM.AreaName = name
  187. _, err = db.Update(&areaM)
  188. sqllog := fmt.Sprintf("修改指定间隔%d的名称为%s", area_id, name)
  189. if err != nil {
  190. logger.Logger.Error(err)
  191. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  192. } else {
  193. new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo())
  194. }
  195. return err
  196. }
  197. //修改指定IED的所属间隔
  198. func (c *CheckAreaMgr) UpdateIedArea(scdid int64, iedname string, area_id int) error {
  199. db := orm.NewOrm()
  200. _, err := db.Raw("update t_data_check_area_ied set area_id=? where scd_id=? and ied_name=?", area_id, scdid, iedname).Exec()
  201. return err
  202. }
  203. //获取指定scd的间隔信息
  204. func (c *CheckAreaMgr) GetAreaList(scdid int64) ([]orm.Params, error) {
  205. db := orm.NewOrm()
  206. 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"
  207. rowset := []orm.Params{}
  208. _, err := db.Raw(sql, scdid).Values(&rowset)
  209. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid})
  210. if err != nil {
  211. logger.Logger.Error(err, sqllog)
  212. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  213. } else {
  214. new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  215. }
  216. return rowset, nil
  217. }
  218. //获取指定scd和电压等级的间隔信息
  219. func (c *CheckAreaMgr) GetAreaListByVol(scdid int64, vl, linkstyleid int) ([]orm.Params, error) {
  220. db := orm.NewOrm()
  221. 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=? "
  222. params := []interface{}{scdid}
  223. if vl > 0 {
  224. sql = sql + " and t1.vol_id=? "
  225. params = append(params, vl)
  226. }
  227. if linkstyleid > 0 {
  228. sql = sql + " and t1.line_link_style=? "
  229. params = append(params, linkstyleid)
  230. }
  231. rowset := []orm.Params{}
  232. _, err := db.Raw(sql+" order by t1.vol_id,t1.line_link_style,t1.id", params).Values(&rowset)
  233. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid, vl})
  234. if err != nil {
  235. logger.Logger.Error(err, sqllog)
  236. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  237. } else {
  238. new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  239. }
  240. return rowset, nil
  241. }
  242. //获取指定间隔下的IED列表
  243. func (c *CheckAreaMgr) GetIedList(scdid int64, areaid int) ([]orm.Params, error) {
  244. db := orm.NewOrm()
  245. 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 "
  246. sqlParamters := []interface{}{}
  247. sqlParamters = append(sqlParamters, scdid)
  248. if areaid > 0 {
  249. sql = sql + " and t1.area_id=?"
  250. sqlParamters = append(sqlParamters, areaid)
  251. }
  252. scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
  253. if serr != nil {
  254. return nil, serr
  255. }
  256. if scdXmlObj == nil {
  257. return nil, errors.New("无效的SCD")
  258. }
  259. rowset := []orm.Params{}
  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_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  265. } else {
  266. scdNode := new(ScdNode)
  267. for i, row := range rowset {
  268. iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), tools.IsEmpty(row["ied_name"]))
  269. if iedObj == nil {
  270. continue
  271. }
  272. rowset[i]["attr_name"] = iedObj.Name
  273. rowset[i]["attr_desc"] = iedObj.Desc
  274. rowset[i]["attr_config_version"] = iedObj.ConfigVersion
  275. rowset[i]["attr_type"] = iedObj.Type
  276. rowset[i]["attr_manufacturer"] = iedObj.Manufacturer
  277. rowset[i]["ied_id"] = iedObj.NodeId
  278. }
  279. //new(SystemLog).Success(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  280. }
  281. return rowset, nil
  282. }
  283. //更新指定间隔下的装置定义
  284. func (c *CheckAreaMgr) UpdateIeds(scdid int64, areaid int, ieds string) error {
  285. db := orm.NewOrm()
  286. iedlist := strings.Split(ieds, ",")
  287. oldInfo := []orm.Params{}
  288. iedNoMap := map[string]orm.Params{}
  289. db.Raw("select * from t_data_check_area_ied where scd_id=? and area_id=?", scdid, areaid).Values(&oldInfo)
  290. for _, row := range oldInfo {
  291. iedNoMap[tools.IsEmpty(row["ied_name"])] = row
  292. }
  293. _, err := db.Raw("delete from t_data_check_area_ied where scd_id=? and area_id=?", scdid, areaid).Exec()
  294. if err != nil {
  295. logger.Logger.Error(err)
  296. return err
  297. }
  298. for _, row := range iedlist {
  299. iedno := tools.IsEmpty(iedNoMap[row]["ied_no"])
  300. iedType := tools.IsEmpty(iedNoMap[row]["ied_type"])
  301. pType := tools.IsEmpty(iedNoMap[row]["p_type"])
  302. if iedType == "" {
  303. iednameParts := new(ScdParse).ParseIedName(row)
  304. iedType = iednameParts[0]
  305. pType = iednameParts[1] + iednameParts[2]
  306. }
  307. _, err = db.Raw("insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_no,ied_type,p_type)values(?,?,?,?,?,?)", scdid, areaid, row, iedno, iedType, pType).Exec()
  308. if err != nil {
  309. logger.Logger.Error(err)
  310. break
  311. }
  312. }
  313. return err
  314. }
  315. //设置间隔下指定装置的端子编号,该编号只有在端子匹配表达式中存在{no}标识时才会使用
  316. func (c *CheckAreaMgr) SetIedNo(areaid int, iedname, no string) error {
  317. db := orm.NewOrm()
  318. _, err := db.Raw("update t_data_check_area_ied set ied_no=? where area_id=? and ied_name=?", no, areaid, iedname).Exec()
  319. return err
  320. }
  321. //获取指定SCD的IED类型列表
  322. func (c *CheckAreaMgr) GetIedTypeList(scdid int64) ([]orm.Params, error) {
  323. db := orm.NewOrm()
  324. 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 "
  325. sqlParamters := []interface{}{}
  326. rowset := []orm.Params{}
  327. sqlParamters = append(sqlParamters, scdid)
  328. _, err := db.Raw(sql, sqlParamters).Values(&rowset)
  329. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
  330. if err != nil {
  331. logger.Logger.Error(err, sqllog)
  332. new(SystemLog).Fail(enum.AuditType_check_area, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  333. }
  334. return rowset, nil
  335. }
  336. func (c *CheckAreaMgr) One(id string) (interface{}, error) {
  337. db := orm.NewOrm()
  338. idInt, err := strconv.ParseInt(id, 10, 64)
  339. if err != nil {
  340. return nil, err
  341. }
  342. areaM := T_data_check_area{Id: idInt}
  343. err = db.Read(&areaM)
  344. if err == nil {
  345. return areaM, nil
  346. }
  347. return nil, err
  348. }
  349. //重置scd的间隔信息
  350. func (c *CheckAreaMgr) Reset() error {
  351. dbo := orm.NewOrm()
  352. dbo.Raw("delete from t_data_check_area where scd_id=?", c.ScdId).Exec()
  353. dbo.Raw("delete from t_data_check_area_ied where scd_id=?", c.ScdId).Exec()
  354. c.ParseModelArea()
  355. logdesc := fmt.Sprintf("重置SCD[%d]检测模型间隔成功", c.ScdId)
  356. new(SystemLog).Success(enum.AuditType_check_task, enum.LogType_bind, enum.OptEventType_Bus, enum.OptEventLevel_Mid, logdesc, c.GetUserInfo())
  357. return nil
  358. }
  359. //生成SCD装置虚端子表
  360. //scdid:SCD文件ID
  361. //areaids:指定的间隔列表。可以不指定,不指定时则生成全站所有装置的端子关系表
  362. //iedname:指定的装置名称。可以不指定。
  363. func (c *CheckAreaMgr) MakeExtrefReport(scdid int64, areaids []string, iedname string) (re []orm.Params, err error) {
  364. findIeds := []orm.Params{}
  365. scdParseMgr := new(ScdParse)
  366. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
  367. if areaids != nil && len(areaids) > 0 {
  368. for _, areaid := range areaids {
  369. if areaid == "" {
  370. continue
  371. }
  372. tmpid, _ := strconv.Atoi(areaid)
  373. r, _ := c.GetIedList(scdid, tmpid)
  374. if r == nil {
  375. continue
  376. }
  377. findIeds = append(findIeds, r...)
  378. }
  379. } else if iedname != "" {
  380. scdParseMgr := new(ScdParse)
  381. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
  382. scdNode := new(ScdNode)
  383. iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname)
  384. if iedObj == nil {
  385. return findIeds, errors.New("无效的装置名称:" + iedname)
  386. }
  387. rowset := orm.Params{"ied_name": iedname}
  388. rowset["attr_name"] = iedObj.Name
  389. rowset["attr_desc"] = iedObj.Desc
  390. rowset["attr_config_version"] = iedObj.ConfigVersion
  391. rowset["attr_type"] = iedObj.Type
  392. rowset["attr_manufacturer"] = iedObj.Manufacturer
  393. rowset["ied_id"] = iedObj.NodeId
  394. findIeds = append(findIeds, rowset)
  395. } else {
  396. //获取所有的装置
  397. for _, iedObj := range scdXmlObj.IED {
  398. rowset := orm.Params{"ied_name": iedObj.Name}
  399. rowset["attr_name"] = iedObj.Name
  400. rowset["attr_desc"] = iedObj.Desc
  401. rowset["attr_config_version"] = iedObj.ConfigVersion
  402. rowset["attr_type"] = iedObj.Type
  403. rowset["attr_manufacturer"] = iedObj.Manufacturer
  404. rowset["ied_id"] = iedObj.NodeId
  405. findIeds = append(findIeds, rowset)
  406. }
  407. }
  408. scdNodeRule := new(ScdNodeRule)
  409. scdNodeRule.SetScdXmlObject(scdXmlObj)
  410. scdNode := new(ScdNode)
  411. //获取端子的外部端子输入信号类型
  412. var getFcdaType = func(inIedObj *node_attr.NIED, t2 *node_attr.NExtRef) string {
  413. isFoundType := false
  414. gooseorsv := ""
  415. for _, ap := range inIedObj.AccessPoint {
  416. if ap.Server == nil {
  417. continue
  418. }
  419. for _, ld := range ap.Server.LDevice {
  420. if ld.LN0 == nil {
  421. continue
  422. }
  423. dsname := ""
  424. for _, ds := range ld.LN0.DataSet {
  425. for _, fcda := range ds.FCDA {
  426. if fcda.LdInst == t2.LdInst && fcda.LnClass == t2.LnClass && fcda.LnInst == t2.LnInst && fcda.Prefix == t2.Prefix && fcda.DoName == t2.DoName {
  427. if t2.DaName == "" || fcda.DaName == t2.DaName {
  428. dsname = ds.Name
  429. break
  430. }
  431. }
  432. }
  433. if dsname != "" {
  434. break
  435. }
  436. }
  437. //logger.Logger.Debug(fmt.Sprintf("%s装置FCDA(%+v)的数据集名称:%s", inIedObj.Name, t2, dsname))
  438. if dsname != "" {
  439. for _, smcrl := range ld.LN0.SampledValueControl {
  440. if smcrl.DatSet == dsname {
  441. gooseorsv = "SV"
  442. break
  443. }
  444. }
  445. if gooseorsv == "" {
  446. for _, goosecrl := range ld.LN0.GSEControl {
  447. if goosecrl.DatSet == dsname {
  448. gooseorsv = "GOOSE"
  449. break
  450. }
  451. }
  452. }
  453. isFoundType = true
  454. break
  455. }
  456. }
  457. if isFoundType {
  458. break
  459. }
  460. }
  461. return gooseorsv
  462. }
  463. //处理ied的端子关系
  464. result := []orm.Params{}
  465. for _, ied := range findIeds {
  466. iedname := tools.IsEmpty(ied["ied_name"])
  467. //获取extref
  468. iedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname)
  469. if iedObj == nil {
  470. logger.Logger.Error(errors.New("装置"+iedname+"未找到"), fmt.Sprintf("装置数据:%+v", ied))
  471. continue
  472. }
  473. for _, t1 := range iedObj.AccessPoint {
  474. if t1.Server == nil || len(t1.Server.LDevice) == 0 {
  475. continue
  476. }
  477. for _, ld := range t1.Server.LDevice {
  478. if ld.LN0 != nil && ld.LN0.Inputs != nil {
  479. for _, t2 := range ld.LN0.Inputs.ExtRef {
  480. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  481. if doi == nil {
  482. logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iedname, t2.IntAddr))
  483. continue
  484. }
  485. itemRow := orm.Params{}
  486. for k, v := range ied {
  487. itemRow[k] = v
  488. }
  489. itemRow["doi_desc"] = doi.(*node_attr.NDOI).Desc
  490. itemRow["doi_addr"] = t2.IntAddr
  491. //获取外部ied信息
  492. iniedname := t2.IedName
  493. inIedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iniedname)
  494. indoi, _ := scdNodeRule.IedFcdaExist(t2.IedName, t2.LdInst, t2.LnClass, t2.LnInst, t2.Prefix, t2.DoName, "")
  495. if inIedObj == nil || indoi == nil {
  496. logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iniedname, t2))
  497. continue
  498. } else {
  499. //查找fcda的数据集及类型
  500. itemRow["gooseorsv"] = getFcdaType(inIedObj, t2)
  501. itemRow["in_ied_name"] = iniedname
  502. itemRow["in_ied_desc"] = inIedObj.Desc
  503. itemRow["in_doi_desc"] = indoi.(*node_attr.NDOI).Desc
  504. daname := ""
  505. if t2.DaName != "" {
  506. daname = "." + t2.DaName
  507. }
  508. itemRow["in_doi_addr"] = fmt.Sprintf("%s/%s%s%s.%s%s", t2.LdInst, t2.Prefix, t2.LnClass, t2.LnInst, t2.DoName, daname)
  509. result = append(result, itemRow)
  510. }
  511. }
  512. }
  513. for _, ln := range ld.LN {
  514. if ln.Inputs == nil {
  515. continue
  516. }
  517. for _, t2 := range ln.Inputs.ExtRef {
  518. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  519. if doi == nil {
  520. logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iedname, t2.IntAddr))
  521. continue
  522. }
  523. itemRow := orm.Params{}
  524. for k, v := range ied {
  525. itemRow[k] = v
  526. }
  527. itemRow["doi_desc"] = doi.(*node_attr.NDOI).Desc
  528. itemRow["doi_addr"] = t2.IntAddr
  529. //获取外部ied信息
  530. iniedname := t2.IedName
  531. inIedObj := scdNode.GetIed(scdXmlObj, tools.IsEmpty(scdid), iniedname)
  532. indoi, _ := scdNodeRule.IedFcdaExist(t2.IedName, t2.LdInst, t2.LnClass, t2.LnInst, t2.Prefix, t2.DoName, "")
  533. if inIedObj == nil || indoi == nil {
  534. logger.Logger.Debug(fmt.Sprintf("未发现装置%s的端子(%+v)名称", iniedname, t2))
  535. continue
  536. }
  537. //查找fcda的数据集及类型
  538. itemRow["gooseorsv"] = getFcdaType(inIedObj, t2)
  539. itemRow["in_ied_name"] = iniedname
  540. itemRow["in_ied_desc"] = inIedObj.Desc
  541. itemRow["in_doi_desc"] = indoi.(*node_attr.NDOI).Desc
  542. daname := ""
  543. if t2.DaName != "" {
  544. daname = "." + t2.DaName
  545. }
  546. itemRow["in_doi_addr"] = fmt.Sprintf("%s/%s%s%s.%s%s", t2.LdInst, t2.Prefix, t2.LnClass, t2.LnInst, t2.DoName, daname)
  547. result = append(result, itemRow)
  548. }
  549. }
  550. }
  551. }
  552. }
  553. return result, nil
  554. }
  555. var areaCheckInfo = sync.Map{}
  556. //获取解析模型需要的基础数据信息
  557. func (c *CheckAreaMgr) getAreaCheckInfo() (*node_attr.SCL, []orm.Params, string, error) {
  558. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  559. if v, h := areaCheckInfo.Load(key); h {
  560. v1 := v.([]interface{})
  561. return v1[0].(*node_attr.SCL), v1[1].([]orm.Params), v1[2].(string), nil
  562. }
  563. arealist := []orm.Params{}
  564. db := orm.NewOrm()
  565. _, err := db.Raw("select id,area_name,area_type,model_id from t_data_check_area where scd_id=?", c.ScdId).Values(&arealist)
  566. if err != nil {
  567. logger.Logger.Error(err)
  568. return nil, nil, "", err
  569. }
  570. scdNodeRule := new(ScdNodeRule)
  571. area_ruleid := ""
  572. area_ruleList, _, _ := scdNodeRule.GetDefList(map[string]interface{}{"check_name": "间隔装置与检查模型不符"}, 1, 1)
  573. if len(area_ruleList) > 0 {
  574. area_ruleid = tools.IsEmpty(area_ruleList[0]["id"])
  575. }
  576. if area_ruleid == "" {
  577. return nil, nil, "", errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  578. }
  579. scdParseMgr := new(ScdParse)
  580. scdXmlObj, serr := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  581. if serr != nil {
  582. return nil, nil, "", serr
  583. }
  584. if scdXmlObj == nil {
  585. return nil, nil, "", errors.New("无效的SCD")
  586. }
  587. areaCheckInfo.Store(key, []interface{}{scdXmlObj, arealist, area_ruleid})
  588. return scdXmlObj, arealist, area_ruleid, nil
  589. }
  590. //检测装置端子分析:检测间隔装置关系正确性(已废弃)
  591. func (c *CheckAreaMgr) CheckAreaIedRelation() error {
  592. // 获取当前scd中需要检查的间隔
  593. scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
  594. db := orm.NewOrm()
  595. if err != nil {
  596. logger.Logger.Error(err)
  597. return err
  598. }
  599. if area_ruleid == "" {
  600. return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  601. }
  602. if scdXmlObj == nil {
  603. return errors.New("无效的SCD")
  604. }
  605. scdNodeRule := new(ScdNodeRule)
  606. scdNode := new(ScdNode)
  607. model_refs := map[string][]orm.Params{} //模型定义的装置关系定义
  608. area_ieds := map[string][]orm.Params{} //间隔下的装置列表
  609. iedRelationMgr := new(SysCheckModelIedRelationMgr)
  610. for _, row := range arealist {
  611. //获取间隔标准装置及关系
  612. modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
  613. //area_name := tools.IsEmpty(row["area_name"])
  614. //area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
  615. area_id := tools.IsEmpty(row["id"])
  616. s, err := iedRelationMgr.GetListByModelid(modelid)
  617. if err != nil {
  618. logger.Logger.Error(err)
  619. return err
  620. }
  621. if len(s) == 0 {
  622. return errors.New(fmt.Sprintf("模型%d还未配置装置关系", modelid))
  623. }
  624. model_refs[fmt.Sprintf("%d", modelid)] = s
  625. /*
  626. hasIeds := map[string]bool{}
  627. for _, row1 := range s {
  628. iedname := tools.IsEmpty(row1["from_ied_code"])
  629. if !hasIeds[iedname] {
  630. hasIeds[iedname] = true
  631. }
  632. iedname = tools.IsEmpty(row1["to_ied_code"])
  633. if !hasIeds[iedname] {
  634. hasIeds[iedname] = true
  635. }
  636. }
  637. */
  638. s1 := []orm.Params{}
  639. _, err = db.Raw("select ied_name from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
  640. if err != nil {
  641. logger.Logger.Error(err)
  642. return err
  643. }
  644. if len(s) == 0 {
  645. return errors.New(fmt.Sprintf("间隔%s未发现任何装置", tools.IsEmpty(row["area_name"])))
  646. }
  647. area_ieds[area_id] = s1
  648. }
  649. //装置关联关系分析
  650. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  651. HasAreaJ := false
  652. for _, row := range arealist {
  653. area_name := tools.IsEmpty(row["area_name"])
  654. areaCode := tools.IsEmpty(row["area_type"]) //间隔模型类型
  655. area_id := tools.IsEmpty(row["id"])
  656. if areaCode == "J" {
  657. HasAreaJ = true
  658. modelid := tools.IsEmpty(row["model_id"])
  659. c.cJ(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PE", area_ruleid)
  660. c.cJ(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PJ", area_ruleid)
  661. c.cJ(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PK", area_ruleid)
  662. c.cJ(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], "PF", area_ruleid)
  663. }
  664. }
  665. for _, row := range arealist {
  666. area_name := tools.IsEmpty(row["area_name"])
  667. areaCode := tools.IsEmpty(row["area_type"]) //间隔模型类型
  668. area_id := tools.IsEmpty(row["id"])
  669. modelid := tools.IsEmpty(row["model_id"])
  670. if areaCode == "J" {
  671. continue
  672. }
  673. if areaCode == "L" {
  674. //线路间隔
  675. c.cL(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], area_ruleid)
  676. }
  677. if areaCode == "T" {
  678. //变压器齐间隔
  679. c.cT(modelid, scdXmlObj, scdNode, scdNodeRule, area_name, model_refs[modelid], area_ieds[area_id], area_ruleid, HasAreaJ)
  680. }
  681. }
  682. scdNodeRule.CheckFinish()
  683. scdNodeRule.Flush()
  684. return nil
  685. }
  686. //检测装置功能分析
  687. func (c *CheckAreaMgr) CheckIedFunc() error {
  688. return nil
  689. }
  690. //检测装置端子分析
  691. func (c *CheckAreaMgr) CheckIedFcda() error {
  692. scdXmlObj, arealist, area_ruleid, err := c.getAreaCheckInfo()
  693. if err != nil {
  694. logger.Logger.Error(err)
  695. return err
  696. }
  697. if area_ruleid == "" {
  698. return errors.New(fmt.Sprintf("未定义间隔装置的检查规则“间隔装置与检查模型不符”"))
  699. }
  700. if scdXmlObj == nil {
  701. return errors.New("无效的SCD")
  702. }
  703. scdidStr := fmt.Sprintf("%d", c.ScdId)
  704. db := orm.NewOrm()
  705. //获取当前站的各电压等级
  706. volRows := []orm.Params{}
  707. _, 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)
  708. if err != nil {
  709. logger.Logger.Error(err)
  710. return err
  711. }
  712. if len(volRows) == 0 {
  713. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  714. return errors.New("该scd未发现任何电压等级的装置")
  715. }
  716. volMap := map[string]string{}
  717. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  718. if len(volRows) == 2 {
  719. volMap["middle"] = ""
  720. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  721. } else {
  722. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  723. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  724. }
  725. scdNodeRule := new(ScdNodeRule)
  726. scdNodeRule.SetScdXmlObject(scdXmlObj)
  727. scdNodeMgr := new(ScdNode)
  728. //当前装置的所有信号接收端子列表
  729. var getIedExtRefs = func(iedname string) map[string]*node_attr.NExtRef {
  730. iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
  731. if iedObj == nil {
  732. logger.Logger.Debug(fmt.Sprintf("在scd:%d中未发现装置%s", c.ScdId, iedname))
  733. return nil
  734. }
  735. fcdaObjList := map[string]*node_attr.NExtRef{}
  736. for _, t1 := range iedObj.AccessPoint {
  737. if t1.Server == nil || len(t1.Server.LDevice) == 0 {
  738. continue
  739. }
  740. for _, ld := range t1.Server.LDevice {
  741. if ld.LN0 != nil && ld.LN0.Inputs != nil {
  742. for _, t2 := range ld.LN0.Inputs.ExtRef {
  743. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  744. if doi == nil {
  745. continue
  746. }
  747. fcdaObjList[doi.(*node_attr.NDOI).Desc] = t2
  748. }
  749. }
  750. for _, ln := range ld.LN {
  751. if ln.Inputs == nil {
  752. continue
  753. }
  754. for _, t2 := range ln.Inputs.ExtRef {
  755. doi := scdNodeRule.IedIntAddrExist(iedname, t2.IntAddr)
  756. if doi == nil {
  757. continue
  758. }
  759. fcdaObjList[doi.(*node_attr.NDOI).Desc] = t2
  760. }
  761. }
  762. }
  763. }
  764. return fcdaObjList
  765. }
  766. //当前装置的所有信号发送端子列表
  767. /*
  768. var getIedFcdas = func(iedname string) map[string]*node_attr.NFCDA {
  769. iedObj := scdNodeMgr.GetIed(scdXmlObj, tools.IsEmpty(c.ScdId), iedname)
  770. if iedObj == nil {
  771. return nil
  772. }
  773. fcdaObjList := map[string]*node_attr.NFCDA{}
  774. for _, t1 := range iedObj.AccessPoint {
  775. if t1.Server == nil || len(t1.Server.LDevice) == 0 {
  776. continue
  777. }
  778. for _, ld := range t1.Server.LDevice {
  779. if ld.LN0 != nil && len(ld.LN0.DataSet) > 0 {
  780. for _, t2 := range ld.LN0.DataSet {
  781. for _, t3 := range t2.FCDA {
  782. re, _ := scdNodeRule.IedFcdaExist(iedname, t3.LdInst, t3.LnClass, t3.LnInst, t3.Prefix, t3.DoName, t3.DaName)
  783. if re == nil {
  784. continue
  785. }
  786. doi := re.(*node_attr.NDOI)
  787. fcdaObjList[doi.Desc] = t3
  788. }
  789. }
  790. }
  791. }
  792. }
  793. return fcdaObjList
  794. }
  795. */
  796. //从装置类型code中解析出类型代码和电压等级
  797. var getIedTypeAndVolCode = func(ied_type string) (string, string) {
  798. tmp := strings.Split(ied_type, "#")
  799. ied_type = tmp[0]
  800. vol := ""
  801. if len(tmp) == 2 {
  802. vol = tmp[1] //电压级别
  803. }
  804. return ied_type, vol
  805. }
  806. //从间隔装置中过滤出指定类型的IED
  807. var filterAreaIeds = func(ied_type, volLevelCode string, s1 []orm.Params, abCode string, isPm ...bool) []orm.Params {
  808. iedlst := []orm.Params{}
  809. if volLevelCode == "" || (volLevelCode != "H" && volLevelCode != "M" && volLevelCode != "L") {
  810. for _, r := range s1 {
  811. iedname := tools.IsEmpty(r["ied_name"])
  812. if strings.HasPrefix(iedname, ied_type) || (abCode != "" && strings.HasSuffix(iedname, abCode)) {
  813. iedlst = append(iedlst, r)
  814. }
  815. }
  816. } else {
  817. tmpLst := map[string]orm.Params{}
  818. for _, r := range s1 {
  819. iedname := tools.IsEmpty(r["ied_name"])
  820. if strings.HasPrefix(iedname, ied_type) || (abCode != "" && strings.HasSuffix(iedname, abCode)) {
  821. tmpLst[iedname] = r
  822. }
  823. }
  824. //PM类型的装置需要单独处理
  825. if len(isPm) > 0 {
  826. //只有1台PM装置时,不用区分电压等级直接返回
  827. if len(tmpLst) == 1 {
  828. for _, r1 := range tmpLst {
  829. return []orm.Params{r1}
  830. }
  831. }
  832. }
  833. h, m, l := c.getIedListByVol(ied_type, tmpLst, volMap, abCode)
  834. if volLevelCode == "H" {
  835. iedlst = h
  836. }
  837. if volLevelCode == "M" {
  838. iedlst = m
  839. }
  840. if volLevelCode == "L" {
  841. iedlst = l
  842. }
  843. }
  844. return iedlst
  845. }
  846. //iedRelationMgr := new(SysCheckModelIedRelationMgr)
  847. modelFcda := sync.Map{}
  848. //已经加载过遥信的装置
  849. isLoadYxIed := map[string]map[*node_attr.NExtRef][]string{}
  850. //已经处理过遥信端子的装置
  851. //isDealYxIed := map[string]int{}
  852. //已获取端子的装置
  853. isLoadExtref := map[string]map[string]*node_attr.NExtRef{}
  854. for _, row := range arealist {
  855. //获取间隔标准装置及关系
  856. modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
  857. area_name := tools.IsEmpty(row["area_name"])
  858. //area_type := tools.IsEmpty(row["area_type"]) //间隔模型类型
  859. area_id := tools.IsEmpty(row["id"])
  860. logger.Logger.Debug(fmt.Sprintf("开始检查模型%d的间隔%s", modelid, area_name))
  861. //获取装置分组信息
  862. bgm := new(SysCheckModelIedtypeGroupMgr)
  863. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  864. groupList := bgm.List()
  865. //获取该间隔模型配置的所有端子关系列表
  866. tmpMgr := new(SysCheckModelFcdaRalationMgr)
  867. tmpMgr.Model.ModelId = modelid
  868. funclist := map[string][]orm.Params{}
  869. key := fmt.Sprintf("%d-%d", modelid, area_id)
  870. v, h := modelFcda.Load(key)
  871. if h {
  872. funclist = v.(map[string][]orm.Params)
  873. } else {
  874. funclist, _ = tmpMgr.GetModelAllFcdaRef()
  875. if funclist == nil || len(funclist) == 0 {
  876. logger.Logger.Error(errors.New(fmt.Sprintf("模型%d下的间隔%s还未配置装置端子关联关系", modelid, area_name)))
  877. continue
  878. }
  879. modelFcda.Store(key, funclist)
  880. }
  881. //获取该间隔下该类型的装置
  882. s1 := []orm.Params{}
  883. _, err = db.Raw("select ied_name,ied_no,'' ied_desc from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
  884. for pos, sr := range s1 {
  885. iedname := tools.IsEmpty(sr["ied_name"])
  886. iedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, iedname)
  887. iedObjDesc := ""
  888. if iedObj != nil {
  889. iedObjDesc = iedObj.Desc
  890. }
  891. s1[pos]["ied_desc"] = iedObjDesc
  892. }
  893. iedExtrefIsExistMap := map[string]int{} //确认已存在的装置端子
  894. typeMappingMgr := new(SysCheckModelIedtypeMappingMgr)
  895. pmCode := c.getIedTypeCode(modelid, "PM")
  896. //循环处理关联关系
  897. for to_ied_type2, refrow := range funclist {
  898. logger.Logger.Debug(fmt.Sprintf("================正在检查类型%s关系===============", to_ied_type2))
  899. ts := strings.Split(to_ied_type2, ",")
  900. //从间隔中获取当前同类型的信号接收装置
  901. ied_type := c.getIedTypeCode(modelid, ts[0])
  902. if v, h := groupList[ied_type]; h {
  903. ied_type = typeMappingMgr.GetMappingType(modelid, v)
  904. }
  905. abCode := c.getIedTypeABCode(ied_type)
  906. ied_type, vol := getIedTypeAndVolCode(ied_type)
  907. isReceivePm := strings.HasPrefix(ied_type, pmCode) //接收装置是Pm装置
  908. iedlst := filterAreaIeds(ied_type, vol, s1, abCode, isReceivePm)
  909. if strings.Index(ts[0], "#0") > 0 {
  910. //本体装置
  911. btIed := []orm.Params{}
  912. for _, r := range iedlst {
  913. ieddesc := tools.IsEmpty(r["ied_desc"])
  914. if strings.Contains(ieddesc, "本休") {
  915. btIed = append(btIed, r)
  916. }
  917. }
  918. iedlst = btIed
  919. }
  920. if strings.Index(ts[0], "#C") > 0 {
  921. //差动装置
  922. btIed := []orm.Params{}
  923. for _, r := range iedlst {
  924. ieddesc := tools.IsEmpty(r["ied_desc"])
  925. if strings.Contains(ieddesc, "差动") {
  926. btIed = append(btIed, r)
  927. }
  928. }
  929. iedlst = btIed
  930. }
  931. logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s与%s的装置(%+v)端子关系", ied_type, vol, ts[1], iedlst))
  932. //从间隔中获取当前信号输出装置
  933. outiedlist := map[string]orm.Params{}
  934. fromiedcode := c.getIedTypeCode(modelid, ts[1])
  935. if v, h := groupList[fromiedcode]; h {
  936. fromiedcode = typeMappingMgr.GetMappingType(modelid, v)
  937. }
  938. fromAbCode := c.getIedTypeABCode(fromiedcode)
  939. from_ied_type, vol2 := getIedTypeAndVolCode(fromiedcode)
  940. isOutPm := strings.HasPrefix(from_ied_type, pmCode) //输出装置是PM装置
  941. outiedlist2 := filterAreaIeds(from_ied_type, vol2, s1, fromAbCode, isOutPm)
  942. for _, iedrow := range outiedlist2 {
  943. iedname := tools.IsEmpty(iedrow["ied_name"])
  944. desc := tools.IsEmpty(iedrow["ied_desc"])
  945. if strings.Index(fromiedcode, "#0") > 0 && strings.Contains(desc, "本休") {
  946. //本体装置
  947. outiedlist[iedname] = iedrow
  948. } else if strings.Index(fromiedcode, "#C") > 0 && strings.Contains(desc, "差动") {
  949. //差动装置
  950. outiedlist[iedname] = iedrow
  951. } else {
  952. outiedlist[iedname] = iedrow
  953. }
  954. }
  955. if len(outiedlist) == 0 {
  956. logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s%s未从类型%s%s的任何电压等级%s装置接收信号", ied_type, vol, abCode, from_ied_type, fromAbCode, vol2))
  957. continue
  958. }
  959. logger.Logger.Debug(fmt.Sprintf("当前装置类型:%s%s的装置(%+v)与类型%s#%s%s存在以下信号输出装置:%+v", ied_type, abCode, iedlst, from_ied_type, fromAbCode, vol2, outiedlist))
  960. //logger.Logger.Debug(fmt.Sprintf("设计端子关联关系:%+v", refrow))
  961. for _, ied := range iedlst {
  962. iedname := tools.IsEmpty(ied["ied_name"])
  963. iedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, iedname)
  964. iedObjDesc := tools.IsEmpty(ied["ied_desc"])
  965. if iedObjDesc == "" {
  966. logger.Logger.Error(fmt.Sprintf("信号接收装置%s未找到!", iedname))
  967. continue
  968. }
  969. //遥信端子列表:仅根据scd实际配置检查其双方端子的doi名称是否相同
  970. scdMgr := new(ScdMgr)
  971. yx, h := isLoadYxIed[iedname]
  972. if !h {
  973. yx = scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
  974. isLoadYxIed[iedname] = yx
  975. }
  976. yxAddrMap := map[string]int{}
  977. for sg, _ := range yx {
  978. key := fmt.Sprintf("%s%s%s%s%s%s%s", sg.IedName, sg.IntAddr, sg.LdInst, sg.Prefix, sg.LnClass, sg.LnInst, sg.DoName)
  979. yxAddrMap[key] = 1
  980. }
  981. //所有端子列表
  982. extreflist := isLoadExtref[iedname]
  983. if extreflist == nil {
  984. extreflist = getIedExtRefs(iedname)
  985. }
  986. for outiedname, outied := range outiedlist {
  987. if iedname == outiedname {
  988. continue
  989. }
  990. //从装置所有的输入端子中过滤出当前输入装置的部分端子
  991. extreflist2 := map[string]*node_attr.NExtRef{}
  992. for desc, item := range extreflist {
  993. if item.IedName == outiedname {
  994. extreflist2[desc] = item
  995. }
  996. }
  997. logger.Logger.Debug(fmt.Sprintf("正在匹配装置%s与%s的端子关联关系", iedname, outiedname))
  998. outIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, outiedname)
  999. outIedObjDesc := ""
  1000. if outIedObj == nil {
  1001. logger.Logger.Error(fmt.Sprintf("信号输出装置%s未找到!", outiedname))
  1002. } else {
  1003. outIedObjDesc = outIedObj.Desc
  1004. }
  1005. if iedObj == nil && outIedObj == nil {
  1006. continue
  1007. }
  1008. //outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
  1009. //检查是否有错误和缺失的端子
  1010. for _, r := range refrow {
  1011. extref_name := tools.IsEmpty(r["to_fcda_name"])
  1012. fcda_name := tools.IsEmpty(r["from_fcda_name"])
  1013. extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
  1014. fcda_name_exp := tools.IsEmpty(r["from_fcda_match_exp"])
  1015. funcName := tools.IsEmpty(r["to_func_name"])
  1016. //端子编号处理
  1017. if strings.Index(extref_name_exp, "{no}") > -1 {
  1018. extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", tools.IsEmpty(ied["ied_no"]))
  1019. }
  1020. if strings.Index(fcda_name_exp, "{no}") > -1 {
  1021. fcda_name_exp = strings.ReplaceAll(fcda_name_exp, "{no}", tools.IsEmpty(outied["ied_no"]))
  1022. }
  1023. funcExist := false //判断接收端设计的端子是否存在
  1024. extrefObj := new(node_attr.NExtRef)
  1025. fcda2Exist := false
  1026. isYx := false
  1027. for desc, item := range extreflist2 {
  1028. if item.IedName != outiedname {
  1029. continue
  1030. }
  1031. //判断是否是遥信端子
  1032. /*
  1033. if strings.Index(funcName, "遥信") > -1 && yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", item.IedName, item.IntAddr, item.LdInst, item.Prefix, item.LnClass, item.LnInst, item.DoName)] == 1 {
  1034. isYx = true
  1035. break
  1036. }
  1037. */
  1038. //logger.Logger.Debug(fmt.Sprintf("接收装置%s的设计端子%s匹配SCD ExtRef DO端子%s", iedname, extref_name_exp, desc))
  1039. macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, desc)
  1040. if macthResult {
  1041. funcExist = true
  1042. extrefObj = item
  1043. extref_name = desc //实际的端子名称
  1044. break
  1045. }
  1046. }
  1047. if isYx {
  1048. //遥信端子不处理
  1049. continue
  1050. }
  1051. if funcExist {
  1052. //判断输出端端子是否存在
  1053. doi, _ := scdNodeRule.IedFcdaExist(extrefObj.IedName, extrefObj.LdInst, extrefObj.LnClass, extrefObj.LnInst, extrefObj.Prefix, extrefObj.DoName, "")
  1054. if doi != nil {
  1055. daname := ""
  1056. if extrefObj.DaName != "" {
  1057. daname = "." + extrefObj.DaName
  1058. }
  1059. fcda2Exist = true
  1060. fcda_name = doi.(*node_attr.NDOI).Desc //实际的端子名称
  1061. if strings.Index(funcName, "遥信") > -1 {
  1062. //2端端子名称需要完全相同
  1063. if extref_name != fcda_name {
  1064. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s关联错误:端子名称不相同", area_name, iedname, extref_name, outiedname, fcda_name)
  1065. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1066. "ied_name": iedname,
  1067. "ied_desc": iedObj.Desc,
  1068. "out_ied_name": outiedname,
  1069. "out_ied_desc": outIedObjDesc,
  1070. "fcda_desc": extref_name,
  1071. "fcda_addr": extrefObj.IntAddr,
  1072. "out_fcda_desc": fcda_name,
  1073. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
  1074. "error_type": "2",
  1075. }
  1076. //检查未通过
  1077. scdNodeRule.AppendFcdaCheckResult(re)
  1078. } else {
  1079. //判断是否是双点或单点遥信端子
  1080. extrefDoi := scdNodeRule.IedIntAddrExist(iedname, extrefObj.IntAddr)
  1081. extrefDoiCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, extrefDoi.(*node_attr.NDOI))
  1082. fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, doi.(*node_attr.NDOI))
  1083. if extrefDoiCdcCode != fcdaCdcCode {
  1084. //错误:cdc类型不一致
  1085. parse_result := fmt.Sprintf("间隔%s的接收装置%s遥信端子%s与输出装置%s端子%s的CDC类型不一致(%s,%s)", area_name, iedname, extrefDoi.(*node_attr.NDOI).Desc, outiedname, doi.(*node_attr.NDOI).Desc, extrefDoiCdcCode, fcdaCdcCode)
  1086. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1087. "ied_name": iedname,
  1088. "ied_desc": iedObj.Desc,
  1089. "out_ied_name": outiedname,
  1090. "out_ied_desc": outIedObjDesc,
  1091. "fcda_desc": extref_name,
  1092. "fcda_addr": extrefObj.IntAddr,
  1093. "out_fcda_desc": fcda_name,
  1094. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
  1095. "error_type": "2",
  1096. }
  1097. //检查未通过
  1098. scdNodeRule.AppendFcdaCheckResult(re)
  1099. }
  1100. }
  1101. continue
  1102. }
  1103. macthResult, _ := tools.RexGroupTestMatch(fcda_name_exp, fcda_name)
  1104. if !macthResult {
  1105. parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误.匹配模式:%s", area_name, iedname, extref_name, outiedname, fcda_name, fcda_name_exp)
  1106. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1107. "ied_name": iedname,
  1108. "ied_desc": iedObj.Desc,
  1109. "out_ied_name": outiedname,
  1110. "out_ied_desc": outIedObjDesc,
  1111. "fcda_desc": extref_name,
  1112. "fcda_addr": extrefObj.IntAddr,
  1113. "out_fcda_desc": fcda_name,
  1114. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
  1115. "error_type": "2",
  1116. }
  1117. //检查未通过
  1118. scdNodeRule.AppendFcdaCheckResult(re)
  1119. }
  1120. }
  1121. }
  1122. if !funcExist {
  1123. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的端子%s定义.匹配模式:%s", area_name, iedname, outiedname, extref_name, extref_name_exp)
  1124. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1125. "ied_name": iedname,
  1126. "ied_desc": iedObjDesc,
  1127. "out_ied_name": outiedname,
  1128. "out_ied_desc": outIedObjDesc,
  1129. "fcda_desc": extref_name,
  1130. "fcda_addr": "",
  1131. "out_fcda_desc": "",
  1132. "out_fcda_addr": "",
  1133. "error_type": "3",
  1134. }
  1135. //检查未通过
  1136. scdNodeRule.AppendFcdaCheckResult(re)
  1137. } else if !fcda2Exist {
  1138. //fcda2Exist为false表示实际的端子from ied不是当前设计的ied
  1139. parse_result := fmt.Sprintf("间隔%s下%s的输入装置%s缺失端子%s.匹配模式:%s", area_name, iedname, outiedname, fcda_name, fcda_name_exp)
  1140. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1141. "ied_name": iedname,
  1142. "ied_desc": iedObjDesc,
  1143. "out_ied_name": outiedname,
  1144. "out_ied_desc": outIedObjDesc,
  1145. "fcda_desc": extref_name,
  1146. "fcda_addr": extrefObj.IntAddr,
  1147. "out_fcda_desc": fcda_name,
  1148. "out_fcda_addr": "",
  1149. "error_type": "3",
  1150. }
  1151. //检查未通过
  1152. scdNodeRule.AppendFcdaCheckResult(re)
  1153. }
  1154. }
  1155. //检查是否有多余(SCD中有不存在于设计中)的端子
  1156. for extrefdesc, r := range extreflist2 { //scd中的端子关系
  1157. //判断是否是当前输入装置和遥信端子
  1158. if r.IedName != outiedname || yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", r.IedName, r.IntAddr, r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName)] == 1 {
  1159. continue
  1160. }
  1161. key := fmt.Sprintf("%s%s", iedname, extrefdesc)
  1162. if iedExtrefIsExistMap[key] == 1 {
  1163. continue
  1164. }
  1165. extref_name := ""
  1166. fcda_name := ""
  1167. isHave := false
  1168. for _, r1 := range refrow { //设计的端子关系
  1169. extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
  1170. if extrefdesc == extref_name_exp {
  1171. //端子存在
  1172. isHave = true
  1173. iedExtrefIsExistMap[key] = 1
  1174. break
  1175. }
  1176. //端子编号处理
  1177. if strings.Index(extref_name_exp, "{no}") > -1 {
  1178. extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", tools.IsEmpty(ied["ied_no"]))
  1179. }
  1180. macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, extrefdesc)
  1181. if macthResult {
  1182. //端子存在
  1183. isHave = true
  1184. iedExtrefIsExistMap[key] = 1
  1185. break
  1186. }
  1187. }
  1188. if !isHave {
  1189. daname := ""
  1190. if r.DaName != "" {
  1191. daname = "." + r.DaName
  1192. }
  1193. doi := scdNodeRule.IedIntAddrExist(iedname, r.IntAddr)
  1194. if doi != nil {
  1195. extref_name = doi.(*node_attr.NDOI).Desc
  1196. }
  1197. doi, _ = scdNodeRule.IedFcdaExist(r.IedName, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
  1198. if doi != nil {
  1199. fcda_name = doi.(*node_attr.NDOI).Desc
  1200. }
  1201. tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, r.IedName)
  1202. parse_result := fmt.Sprintf("间隔%s下装置(%s)的端子%s在设计中不存在", area_name, iedname, extref_name)
  1203. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1204. "ied_name": iedname,
  1205. "ied_desc": iedObj.Desc,
  1206. "out_ied_name": r.IedName,
  1207. "out_ied_desc": tmpIedObj.Desc,
  1208. "fcda_desc": extref_name,
  1209. "fcda_addr": r.IntAddr,
  1210. "out_fcda_desc": fcda_name,
  1211. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName, daname),
  1212. "error_type": "1",
  1213. }
  1214. //检查未通过
  1215. scdNodeRule.AppendFcdaCheckResult(re)
  1216. }
  1217. }
  1218. }
  1219. //判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
  1220. //遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致以及单双点类型是否相同,以及是否有缺失和多余的遥信端子
  1221. /*
  1222. if len(yx) > 0 && isDealYxIed[iedname] == 0 {
  1223. //logger.Logger.Debug(fmt.Sprintf("=============正在处理装置%s遥信端子数:%d %+v", iedname, len(yx), isDealYxIed))
  1224. isDealYxIed[iedname] = 1
  1225. for extref, doiinfo := range yx {
  1226. doiDesc := doiinfo[0]
  1227. doiCdc := doiinfo[1]
  1228. daname := ""
  1229. if extref.DaName != "" {
  1230. daname = "." + extref.DaName
  1231. }
  1232. //获取输出端端子名称
  1233. outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
  1234. tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, extref.IedName)
  1235. if tmpIedObj == nil || outFcdaDoi == nil {
  1236. //端子缺失
  1237. tmpIedName := ""
  1238. tmpIedDesc := ""
  1239. if tmpIedObj != nil {
  1240. tmpIedName = tmpIedObj.Name
  1241. tmpIedDesc = tmpIedObj.Desc
  1242. }
  1243. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s的关联端子不存在", area_name, iedname, doiDesc)
  1244. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1245. "ied_name": iedname,
  1246. "ied_desc": iedObj.Desc,
  1247. "out_ied_name": tmpIedName,
  1248. "out_ied_desc": tmpIedDesc,
  1249. "fcda_desc": doiDesc,
  1250. "fcda_addr": extref.IntAddr,
  1251. "out_fcda_desc": "",
  1252. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1253. "error_type": "3",
  1254. }
  1255. //检查未通过
  1256. scdNodeRule.AppendFcdaCheckResult(re)
  1257. continue
  1258. }
  1259. if doiCdc != "" && (!YaoXinDBType[doiCdc] || !YaoXinSiType[doiCdc]) {
  1260. //判断是否是双点或单点遥信端子
  1261. fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, outFcdaDoi.(*node_attr.NDOI))
  1262. if doiCdc != fcdaCdcCode {
  1263. //错误:cdc类型不一致
  1264. parse_result := fmt.Sprintf("间隔%s的接收装置%s遥信端子%s与输出装置%s端子%s的CDC类型不一致(%s,%s)", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc, doiCdc, fcdaCdcCode)
  1265. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1266. "ied_name": iedname,
  1267. "ied_desc": iedObj.Desc,
  1268. "out_ied_name": tmpIedObj.Name,
  1269. "out_ied_desc": tmpIedObj.Desc,
  1270. "fcda_desc": doiDesc,
  1271. "fcda_addr": extref.IntAddr,
  1272. "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
  1273. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1274. "error_type": "2",
  1275. }
  1276. //检查未通过
  1277. scdNodeRule.AppendFcdaCheckResult(re)
  1278. continue
  1279. }
  1280. }
  1281. if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
  1282. //关联错误
  1283. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc)
  1284. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1285. "ied_name": iedname,
  1286. "ied_desc": iedObj.Desc,
  1287. "out_ied_name": tmpIedObj.Name,
  1288. "out_ied_desc": tmpIedObj.Desc,
  1289. "fcda_desc": doiDesc,
  1290. "fcda_addr": extref.IntAddr,
  1291. "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
  1292. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1293. "error_type": "2",
  1294. }
  1295. //检查未通过
  1296. scdNodeRule.AppendFcdaCheckResult(re)
  1297. }
  1298. }
  1299. }
  1300. */
  1301. yxAddrMap = nil
  1302. extreflist = nil
  1303. }
  1304. }
  1305. }
  1306. isLoadYxIed = nil
  1307. scdNodeRule.CheckFinish()
  1308. scdNodeRule.Flush()
  1309. return nil
  1310. }
  1311. //解析模型间隔。根据模型定义解析出间隔中的装置
  1312. func (c *CheckAreaMgr) ParseModelArea() {
  1313. c.Init(c.ScdId)
  1314. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  1315. areaCheckInfo.Delete(key)
  1316. // 取得当前scd所有ied及名称解析结果
  1317. dbo := orm.NewOrm()
  1318. 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"
  1319. iedlst := []orm.Params{}
  1320. _, err := dbo.Raw(sql, c.ScdId).Values(&iedlst)
  1321. if err != nil {
  1322. logger.Logger.Error(err)
  1323. return
  1324. }
  1325. logger.Logger.Debug(fmt.Sprintf("=====总装置数:%d", len(iedlst)))
  1326. iedMap := map[string]orm.Params{}
  1327. for _, r := range iedlst {
  1328. iedMap[tools.IsEmpty(r["ied_name"])] = r
  1329. }
  1330. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  1331. HasAreaJ := false
  1332. for _, row := range c.CheckModelList {
  1333. areaCode := tools.IsEmpty(row["area_type_code"])
  1334. if areaCode == "J" {
  1335. HasAreaJ = true
  1336. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  1337. //modelname := tools.IsEmpty(row["model_name"])
  1338. iedtypes := tools.IsEmpty(row["ied_types"])
  1339. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1340. mapptype.Model = T_data_model_iedtype_mapping{ModelId: modelid}
  1341. mappresult := mapptype.List()
  1342. if len(mappresult) > 0 {
  1343. tmp := []string{}
  1344. for _, r := range strings.Split(iedtypes, ",") {
  1345. if mappresult[r] != "" {
  1346. tmp = append(tmp, mappresult[r])
  1347. } else {
  1348. tmp = append(tmp, r)
  1349. }
  1350. }
  1351. iedtypes = strings.Join(tmp, ",")
  1352. }
  1353. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  1354. c.pJ(modelid, volcode, iedtypes, iedMap, "PE")
  1355. c.pJ(modelid, volcode, iedtypes, iedMap, "PJ")
  1356. c.pJ(modelid, volcode, iedtypes, iedMap, "PK")
  1357. c.pJ(modelid, volcode, iedtypes, iedMap, "PF")
  1358. }
  1359. }
  1360. for _, row := range c.CheckModelList {
  1361. //逐一分析模型定义
  1362. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  1363. modelname := tools.IsEmpty(row["model_name"])
  1364. iedtypes := tools.IsEmpty(row["ied_types"])
  1365. //模型对应的间隔代码
  1366. /*
  1367. S 站用变压器
  1368. C 电容器
  1369. B 断路器
  1370. K 母分
  1371. J 母联
  1372. M 母线
  1373. X 电抗器
  1374. L 线路
  1375. T 主变压器
  1376. */
  1377. areaCode := tools.IsEmpty(row["area_type_code"])
  1378. //模型对应的电压等级
  1379. //10:10KV 35:35KV 66:66KV 11:110KV 22:220KV 50:500KV 75:750KV 33:330KV T0:1000KV
  1380. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  1381. if modelname == "" || iedtypes == "" {
  1382. continue
  1383. }
  1384. //母联间隔已经提前分析,如果没有母联间隔时,主变间隔中不包含母联终端装置
  1385. if areaCode == "J" {
  1386. continue
  1387. }
  1388. //获取模型中的自定义装置类型编码
  1389. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1390. mapptype.Model = T_data_model_iedtype_mapping{ModelId: modelid}
  1391. mappresult := mapptype.List()
  1392. if len(mappresult) > 0 {
  1393. tmp := []string{}
  1394. for _, r := range strings.Split(iedtypes, ",") {
  1395. if mappresult[r] != "" {
  1396. tmp = append(tmp, mappresult[r])
  1397. } else {
  1398. tmp = append(tmp, r)
  1399. }
  1400. }
  1401. iedtypes = strings.Join(tmp, ",")
  1402. }
  1403. //获取模型内中装备关系定义
  1404. //主变间隔分析:需要查站内该电压等级下的高中低压侧装置或者高低压装置组成一个间隔,以主变保护装置(PT)为起始
  1405. if areaCode == "T" {
  1406. c.pT(modelid, volcode, iedtypes, iedMap, HasAreaJ)
  1407. }
  1408. //线路保护间隔分析:以线路保护测控装置(PL)为开始分析
  1409. if areaCode == "L" {
  1410. c.pL(modelid, volcode, iedtypes, iedMap)
  1411. }
  1412. //母线间隔分析:PM
  1413. if areaCode == "M" {
  1414. c.pM(modelid, volcode, iedtypes, iedMap)
  1415. }
  1416. }
  1417. }
  1418. //根据默认装置类型获取其类型编码。如果没有自定义编码,则返回默认编码。返回编码时已自动去除套别标识
  1419. func (c *CheckAreaMgr) getIedTypeCode(modelid int, iedtype string) string {
  1420. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1421. mappresult := mapptype.GetMappingType(modelid, iedtype)
  1422. ptCode := iedtype
  1423. if mappresult != "" {
  1424. ptCode = mappresult //自定义主变保护编码
  1425. }
  1426. return strings.Split(ptCode, "-")[0]
  1427. }
  1428. //变压器间隔分析
  1429. func (c *CheckAreaMgr) pT(modelid int, vol, iedtypes string, ieds map[string]orm.Params, HasAreaJ bool) {
  1430. scdParseMgr := new(ScdParse)
  1431. scdNodeMgr := new(ScdNode)
  1432. db := orm.NewOrm()
  1433. //获取装置分组信息
  1434. bgm := new(SysCheckModelIedtypeGroupMgr)
  1435. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1436. groupList := bgm.List()
  1437. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1438. //获取当前站的各电压等级
  1439. volRows := []orm.Params{}
  1440. _, 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)
  1441. if err != nil {
  1442. logger.Logger.Error(err)
  1443. return
  1444. }
  1445. if len(volRows) == 0 {
  1446. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  1447. return
  1448. }
  1449. volMap := map[string]string{}
  1450. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  1451. if len(volRows) == 2 {
  1452. volMap["middle"] = ""
  1453. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  1454. } else {
  1455. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  1456. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  1457. }
  1458. var getIedByDesc = func(iedinfo map[string]orm.Params, iedtpye string, desc string) ([]string, []string) {
  1459. scdParseMgr := new(ScdParse)
  1460. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1461. r1 := []string{}
  1462. r2 := []string{}
  1463. for vn, row := range iedinfo {
  1464. if strings.HasPrefix(vn, iedtpye) {
  1465. v := tools.IsEmpty(row["ied_desc"])
  1466. if v == "" {
  1467. if scdXmlObj == nil {
  1468. continue
  1469. }
  1470. scdNode := new(ScdNode)
  1471. ied := scdNode.GetIed(scdXmlObj, "", vn)
  1472. if ied == nil {
  1473. continue
  1474. }
  1475. v = ied.Desc
  1476. }
  1477. if strings.Contains(v, desc) {
  1478. r1 = append(r1, v)
  1479. r2 = append(r2, vn)
  1480. }
  1481. }
  1482. }
  1483. return r1, r2
  1484. }
  1485. //判断是否将各电压等级的保护装置合并还是分开的间隔
  1486. //如果存在高中低压的保护装置,则说明是分开的主变间隔
  1487. ptCode := c.getIedTypeCode(modelid, "PT")
  1488. volValue := "" //电压等级值
  1489. if strings.Index(","+iedtypes+",", ","+ptCode+",") == -1 {
  1490. //判断主变保护是否是按电压等级分开配置的模型
  1491. h, m, l := c.getIedListByVol(ptCode, ieds, volMap)
  1492. if strings.Contains(iedtypes, ptCode+"#H") && len(h) > 0 {
  1493. //高压侧装置
  1494. volValue = "H"
  1495. } else if strings.Contains(iedtypes, ptCode+"#M") && len(m) > 0 {
  1496. volValue = "M"
  1497. } else if strings.Contains(iedtypes, ptCode+"#L") && len(l) > 0 {
  1498. volValue = "L"
  1499. }
  1500. }
  1501. pmCode := c.getIedTypeCode(modelid, "PM")
  1502. mmCode := c.getIedTypeCode(modelid, "MM")
  1503. ctCode := c.getIedTypeCode(modelid, "CT")
  1504. delPm := false
  1505. delMm := false
  1506. for _, row := range ieds {
  1507. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != ptCode[0:1] || tools.IsEmpty(row["p_type"]) != ptCode[1:] {
  1508. continue
  1509. }
  1510. if _, h := groupList[ptCode]; h {
  1511. //装置如果是分组成员装置,则不用检测
  1512. continue
  1513. }
  1514. pl_iedname := tools.IsEmpty(row["ied_name"])
  1515. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1516. areadesc := tools.IsEmpty(row["ied_desc"])
  1517. if areadesc == "" {
  1518. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1519. if iedobj != nil {
  1520. areadesc = iedobj.Desc
  1521. } else {
  1522. areadesc = tools.IsEmpty(row["area_name"])
  1523. }
  1524. }
  1525. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1526. //添加间隔数据
  1527. dbdata := T_data_check_area{
  1528. ModelId: modelid,
  1529. ScdId: c.ScdId,
  1530. AreaType: "T",
  1531. AreaName: areadesc + iednameParts[7],
  1532. }
  1533. newid, err := db.Insert(&dbdata)
  1534. if err != nil {
  1535. logger.Logger.Error(err)
  1536. return
  1537. }
  1538. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1539. insvalues := []string{}
  1540. inAreaIedName := ""
  1541. hasIedNameMap := map[string]int{}
  1542. //insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "T"))
  1543. for _, ty := range strings.Split(iedtypes, ",") {
  1544. inAreaIedName = ""
  1545. if _, h := groupList[ty]; h {
  1546. //装置如果是分组成员装置,则不用检测
  1547. continue
  1548. }
  1549. //判断是否指定的套别标识
  1550. abCode := c.getIedTypeABCode(ty)
  1551. if abCode != "" {
  1552. iednameParts[7] = abCode
  1553. }
  1554. tyCode := c.getIedTypeCode(modelid, ty)
  1555. if _, h := groupList[tyCode]; h {
  1556. //装置如果是分组成员装置,则不用检测
  1557. continue
  1558. }
  1559. if tyCode[0:len(pmCode)] == pmCode {
  1560. //PM和MM最后处理
  1561. delPm = true
  1562. continue
  1563. }
  1564. if tyCode[0:len(mmCode)] == mmCode {
  1565. //PM和MM最后处理
  1566. delMm = true
  1567. continue
  1568. }
  1569. ptype := strings.Split(tyCode, "#")[0]
  1570. //判断间隔是否需要包含差动装置
  1571. if strings.Contains(tyCode, "#C") {
  1572. _, iedname := getIedByDesc(ieds, ptype, "差动")
  1573. if len(iedname) > 0 {
  1574. for _, in := range iedname {
  1575. tmpIednameParts := scdParseMgr.ParseIedName(in)
  1576. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1577. if hasIedNameMap[in] == 1 {
  1578. break
  1579. }
  1580. hasIedNameMap[in] = 1
  1581. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
  1582. break
  1583. }
  1584. }
  1585. }
  1586. continue
  1587. }
  1588. //判断间隔是否需要包含本体保护装置
  1589. if strings.Contains(tyCode, "#0") {
  1590. _, iedname := getIedByDesc(ieds, ptype, "本体")
  1591. if len(iedname) > 0 {
  1592. for _, in := range iedname {
  1593. tmpIednameParts := scdParseMgr.ParseIedName(in)
  1594. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1595. if hasIedNameMap[in] == 1 {
  1596. break
  1597. }
  1598. hasIedNameMap[in] = 1
  1599. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
  1600. break
  1601. }
  1602. }
  1603. }
  1604. continue
  1605. }
  1606. dlIeds := []orm.Params{}
  1607. imtcode := c.getIedTypeCode(modelid, tyCode)
  1608. h, m, l := c.getIedListByVol(imtcode, ieds, volMap, abCode)
  1609. //logger.Logger.Debug(fmt.Sprintf("tyCode:%s H:%+v,M:%+v,L:%+v", tyCode, h, m, l))
  1610. if volValue == "" || volValue == "H" || strings.Contains(tyCode, "#H") {
  1611. dlIeds = append(dlIeds, h...)
  1612. }
  1613. if volValue == "" || volValue == "M" || strings.Contains(tyCode, "#M") {
  1614. dlIeds = append(dlIeds, m...)
  1615. }
  1616. if volValue == "" || volValue == "L" || strings.Contains(tyCode, "#L") {
  1617. dlIeds = append(dlIeds, l...)
  1618. }
  1619. for _, r := range dlIeds {
  1620. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1621. if hasIedNameMap[inAreaIedName] == 1 {
  1622. continue
  1623. }
  1624. hasIedNameMap[inAreaIedName] = 1
  1625. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1626. if tyCode[0:len(ctCode)] == ctCode {
  1627. //CT单独处理。它可能不分AB套
  1628. lastChar := tmpIednameParts[7]
  1629. if tmpIednameParts[6] == iednameParts[6] && (lastChar == "" || lastChar == iednameParts[7]) {
  1630. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1631. }
  1632. } else {
  1633. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1634. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1635. }
  1636. }
  1637. }
  1638. }
  1639. //最后处理PM和MM
  1640. inAreaIedName = c.getPMName(iednameParts, ieds)
  1641. if delPm && inAreaIedName != "" {
  1642. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1643. //pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1644. //使用PM装置的名称去定义MM的名称
  1645. inAreaIedName = c.getMMName(iednameParts, ieds, iednameParts[7])
  1646. if delMm && inAreaIedName != "" {
  1647. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M"))
  1648. }
  1649. }
  1650. //写数据库
  1651. if len(insvalues) > 0 {
  1652. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1653. }
  1654. if err != nil {
  1655. logger.Logger.Error(err)
  1656. return
  1657. }
  1658. }
  1659. }
  1660. //线路间隔分析
  1661. //vol:电压等级
  1662. func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1663. scdParseMgr := new(ScdParse)
  1664. scdNodeMgr := new(ScdNode)
  1665. db := orm.NewOrm()
  1666. //获取装置分组信息
  1667. bgm := new(SysCheckModelIedtypeGroupMgr)
  1668. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1669. groupList := bgm.List()
  1670. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1671. iedCode := c.getIedTypeCode(modelid, "PL")
  1672. for _, row := range ieds {
  1673. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != iedCode[0:1] || tools.IsEmpty(row["p_type"]) != iedCode[1:] {
  1674. continue
  1675. }
  1676. mmIedName := ""
  1677. pl_iedname := tools.IsEmpty(row["ied_name"])
  1678. if _, h := groupList[pl_iedname]; h {
  1679. //装置如果是分组成员装置,则不用检测
  1680. continue
  1681. }
  1682. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1683. areadesc := tools.IsEmpty(row["ied_desc"])
  1684. if areadesc == "" {
  1685. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1686. if iedobj != nil {
  1687. areadesc = iedobj.Desc
  1688. } else {
  1689. areadesc = tools.IsEmpty(row["area_name"])
  1690. }
  1691. }
  1692. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1693. //添加间隔数据
  1694. dbdata := T_data_check_area{
  1695. ModelId: modelid,
  1696. ScdId: c.ScdId,
  1697. AreaType: "L",
  1698. AreaName: areadesc + iednameParts[7],
  1699. }
  1700. newid, err := db.Insert(&dbdata)
  1701. if err != nil {
  1702. logger.Logger.Error(err)
  1703. return
  1704. }
  1705. hasIedNameMap := map[string]int{}
  1706. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1707. insvalues := []string{}
  1708. pmCode := c.getIedTypeCode(modelid, "PM")
  1709. mmCode := c.getIedTypeCode(modelid, "MM")
  1710. clCode := c.getIedTypeCode(modelid, "CL")
  1711. for _, ty := range strings.Split(iedtypes, ",") {
  1712. inAreaIedName := ""
  1713. if _, h := groupList[ty]; h {
  1714. //装置如果是分组成员装置,则不用检测
  1715. continue
  1716. }
  1717. abCode := c.getIedTypeABCode(ty)
  1718. if abCode != "" {
  1719. iednameParts[7] = abCode
  1720. }
  1721. tyCode := c.getIedTypeCode(modelid, ty)
  1722. if _, h := groupList[tyCode]; h {
  1723. //装置如果是分组成员装置,则不用检测
  1724. continue
  1725. }
  1726. ptype := strings.Split(tyCode, "#")[0]
  1727. if ptype == pmCode {
  1728. //母线保护和母线合并单元装置编号跟随变压器
  1729. //查找变压器编号
  1730. //1号变压器->2号变压器->3号
  1731. inAreaIedName = c.getPMName(iednameParts, ieds)
  1732. if hasIedNameMap[inAreaIedName] == 1 {
  1733. continue
  1734. }
  1735. hasIedNameMap[inAreaIedName] = 1
  1736. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:2]))
  1737. continue
  1738. } else if ptype == mmCode {
  1739. //最后处理
  1740. continue
  1741. } else {
  1742. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1743. }
  1744. if strings.Index("ABCDE", iednameParts[7]) > -1 {
  1745. //最后一位是字母则说明是AB套
  1746. switch ptype {
  1747. case clCode:
  1748. if strings.Contains(iedtypes, "PLC") || strings.Contains(iedtypes, "PCL") {
  1749. //不处理CL装置
  1750. } else {
  1751. //测控装置,先判断是否分了AB套,没有标识(ied名称的最后一位是否是字母)则说明是多套共用装置
  1752. if ieds[inAreaIedName] == nil {
  1753. //当前测控装置没有分AB套
  1754. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1755. }
  1756. }
  1757. break
  1758. default:
  1759. break
  1760. }
  1761. }
  1762. if hasIedNameMap[inAreaIedName] == 1 {
  1763. continue
  1764. }
  1765. hasIedNameMap[inAreaIedName] = 1
  1766. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1767. }
  1768. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1769. if err != nil {
  1770. logger.Logger.Error(err)
  1771. return
  1772. }
  1773. //如果mm装置还未确定
  1774. if mmIedName == "" {
  1775. //pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1776. inAreaIedName := c.getMMName(iednameParts, ieds, iednameParts[7])
  1777. _, err = db.Raw(ins1 + fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M")).Exec()
  1778. if err != nil {
  1779. logger.Logger.Error(err)
  1780. return
  1781. }
  1782. }
  1783. }
  1784. }
  1785. //母联间隔分析
  1786. func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm.Params, pjIed string) {
  1787. scdParseMgr := new(ScdParse)
  1788. scdNodeMgr := new(ScdNode)
  1789. db := orm.NewOrm()
  1790. pjIed = c.getIedTypeCode(modelid, pjIed)
  1791. scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1792. for _, row := range ieds {
  1793. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != pjIed[0:1] || tools.IsEmpty(row["p_type"]) != pjIed[1:2] {
  1794. continue
  1795. }
  1796. pmIedName := ""
  1797. mmIedName := ""
  1798. pl_iedname := tools.IsEmpty(row["ied_name"])
  1799. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1800. areadesc := tools.IsEmpty(row["ied_desc"])
  1801. if areadesc == "" {
  1802. iedobj := scdNodeMgr.GetIed(scdXmlObject, "", pl_iedname)
  1803. if iedobj != nil {
  1804. areadesc = iedobj.Desc
  1805. } else {
  1806. areadesc = tools.IsEmpty(row["area_name"])
  1807. }
  1808. }
  1809. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1810. //添加间隔数据
  1811. dbdata := T_data_check_area{
  1812. ModelId: modelid,
  1813. ScdId: c.ScdId,
  1814. AreaType: "J",
  1815. AreaName: areadesc + iednameParts[7],
  1816. }
  1817. newid, err := db.Insert(&dbdata)
  1818. if err != nil {
  1819. logger.Logger.Error(err)
  1820. return
  1821. }
  1822. hasIedNameMap := map[string]int{}
  1823. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1824. insvalues := []string{}
  1825. pmCode := c.getIedTypeCode(modelid, "PM")
  1826. mmCode := c.getIedTypeCode(modelid, "MM")
  1827. for _, ty := range strings.Split(iedtypes, ",") {
  1828. abCode := c.getIedTypeABCode(ty)
  1829. if abCode != "" {
  1830. iednameParts[7] = abCode
  1831. }
  1832. tyCode := c.getIedTypeCode(modelid, ty)
  1833. ptype := strings.Split(tyCode, "#")[0]
  1834. inAreaIedName := ""
  1835. if ptype == pmCode {
  1836. //母线保护和母线合并单元装置编号跟随变压器
  1837. //查找变压器编号
  1838. //1号变压器->2号变压器->3号
  1839. inAreaIedName = c.getPMName(iednameParts, ieds)
  1840. pmIedName = inAreaIedName
  1841. if mmIedName == "" {
  1842. if hasIedNameMap[inAreaIedName] == 1 {
  1843. continue
  1844. }
  1845. hasIedNameMap[inAreaIedName] = 1
  1846. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1847. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1848. //使用PM装置的名称去定义MM的名称
  1849. tyCode = "MM"
  1850. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1851. mmIedName = inAreaIedName
  1852. }
  1853. } else if ptype == mmCode {
  1854. if pmIedName != "" && mmIedName == "" {
  1855. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1856. //使用PM装置的名称去定义MM的名称
  1857. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1858. mmIedName = inAreaIedName
  1859. } else {
  1860. continue
  1861. }
  1862. } else {
  1863. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1864. //判断与基准保护装置相同套号的装置是否存在
  1865. if ieds[inAreaIedName] == nil {
  1866. //尝试去除套号
  1867. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1868. }
  1869. }
  1870. if hasIedNameMap[inAreaIedName] == 1 {
  1871. continue
  1872. }
  1873. hasIedNameMap[inAreaIedName] = 1
  1874. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1875. }
  1876. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1877. if err != nil {
  1878. logger.Logger.Error(err)
  1879. return
  1880. }
  1881. }
  1882. }
  1883. //母线间隔装置提取
  1884. func (c *CheckAreaMgr) pM(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1885. scdParseMgr := new(ScdParse)
  1886. scdNodeMgr := new(ScdNode)
  1887. db := orm.NewOrm()
  1888. //获取当前站的各电压等级
  1889. volRows := []orm.Params{}
  1890. _, 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)
  1891. if err != nil {
  1892. logger.Logger.Error(err)
  1893. return
  1894. }
  1895. if len(volRows) == 0 {
  1896. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  1897. return
  1898. }
  1899. volMap := map[string]string{}
  1900. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  1901. if len(volRows) == 2 {
  1902. volMap["middle"] = ""
  1903. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  1904. } else {
  1905. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  1906. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  1907. }
  1908. //获取装置分组信息
  1909. bgm := new(SysCheckModelIedtypeGroupMgr)
  1910. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1911. groupList := bgm.List()
  1912. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1913. iedCode := c.getIedTypeCode(modelid, "PM")
  1914. for _, row := range ieds {
  1915. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != iedCode[0:1] || tools.IsEmpty(row["p_type"]) != iedCode[1:] {
  1916. continue
  1917. }
  1918. pl_iedname := tools.IsEmpty(row["ied_name"])
  1919. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1920. areadesc := tools.IsEmpty(row["ied_desc"])
  1921. if areadesc == "" {
  1922. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1923. if iedobj != nil {
  1924. areadesc = iedobj.Desc
  1925. } else {
  1926. areadesc = tools.IsEmpty(row["area_name"])
  1927. }
  1928. }
  1929. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1930. //添加间隔数据
  1931. dbdata := T_data_check_area{
  1932. ModelId: modelid,
  1933. ScdId: c.ScdId,
  1934. AreaType: "M",
  1935. AreaName: areadesc,
  1936. }
  1937. newid, err := db.Insert(&dbdata)
  1938. if err != nil {
  1939. logger.Logger.Error(err)
  1940. return
  1941. }
  1942. pmVol := "" //当前PM装置的电压等级
  1943. for volLevel, volValue := range volMap {
  1944. if volValue == iednameParts[3]+iednameParts[4] {
  1945. pmVol = volLevel
  1946. break
  1947. }
  1948. }
  1949. hasIedNameMap := map[string]int{}
  1950. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1951. insvalues := []string{}
  1952. mmCode := c.getIedTypeCode(modelid, "MM")
  1953. for _, ty := range strings.Split(iedtypes, ",") {
  1954. inAreaIedName := ""
  1955. if _, h := groupList[ty]; h {
  1956. //装置如果是分组成员装置,则不用检测
  1957. continue
  1958. }
  1959. abCode := c.getIedTypeABCode(ty)
  1960. if abCode == "" {
  1961. //未特别指定套别时,采用主IED装置的套别
  1962. abCode = iednameParts[7]
  1963. }
  1964. tyCode := c.getIedTypeCode(modelid, ty)
  1965. if _, h := groupList[tyCode]; h {
  1966. //装置如果是分组成员装置,则不用检测
  1967. continue
  1968. }
  1969. ptype := strings.Split(tyCode, "#")[0]
  1970. if tyCode == mmCode {
  1971. //MM:母线合并单元
  1972. inAreaIedName = c.getMMName(iednameParts, ieds, abCode)
  1973. if inAreaIedName != "" {
  1974. if hasIedNameMap[inAreaIedName] == 1 {
  1975. continue
  1976. }
  1977. hasIedNameMap[inAreaIedName] = 1
  1978. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1979. }
  1980. } else {
  1981. //需要查找同电压等级的所有同类同套装置
  1982. h, m, l := c.getIedListByVol(tyCode, ieds, volMap, abCode)
  1983. //logger.Logger.Debug(fmt.Sprintf("当前PM装置:%s 电压等级:%s 提取类型:%s 套别:%s h:%+v,m:%+v,l:%+v", pl_iedname, pmVol, ptype, abCode, h, m, l))
  1984. switch pmVol {
  1985. case "hight":
  1986. for _, item := range h {
  1987. inAreaIedName = tools.IsEmpty(item["ied_name"])
  1988. if hasIedNameMap[inAreaIedName] == 1 {
  1989. continue
  1990. }
  1991. hasIedNameMap[inAreaIedName] = 1
  1992. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1993. }
  1994. break
  1995. case "middle":
  1996. for _, item := range m {
  1997. inAreaIedName = tools.IsEmpty(item["ied_name"])
  1998. if hasIedNameMap[inAreaIedName] == 1 {
  1999. continue
  2000. }
  2001. hasIedNameMap[inAreaIedName] = 1
  2002. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  2003. }
  2004. break
  2005. case "low":
  2006. for _, item := range l {
  2007. inAreaIedName = tools.IsEmpty(item["ied_name"])
  2008. if hasIedNameMap[inAreaIedName] == 1 {
  2009. continue
  2010. }
  2011. hasIedNameMap[inAreaIedName] = 1
  2012. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  2013. }
  2014. break
  2015. }
  2016. }
  2017. }
  2018. if len(insvalues) == 0 {
  2019. continue
  2020. }
  2021. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  2022. if err != nil {
  2023. logger.Logger.Error(err)
  2024. return
  2025. }
  2026. }
  2027. }
  2028. //母联间隔装置关系检查
  2029. 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) {
  2030. modelidInt, _ := strconv.Atoi(modelid)
  2031. pjIed = c.getIedTypeCode(modelidInt, pjIed)
  2032. masterIed := new(node_attr.NIED)
  2033. findIedName := ""
  2034. for _, row2 := range area_ieds {
  2035. findIedName = tools.IsEmpty(row2["ied_name"])
  2036. if strings.HasPrefix(findIedName, pjIed) {
  2037. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2038. break
  2039. }
  2040. }
  2041. if masterIed == nil {
  2042. return
  2043. }
  2044. dealFromIed := map[string]int{}
  2045. for _, row := range ied_refs {
  2046. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  2047. toiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"]))
  2048. reftype := tools.IsEmpty(row["in_type"])
  2049. tmpFromAreaIeds := []orm.Params{}
  2050. tmpToAreaIeds := []orm.Params{}
  2051. for _, row2 := range area_ieds {
  2052. findIedName = tools.IsEmpty(row2["ied_name"])
  2053. if strings.HasPrefix(findIedName, fromiedtype) {
  2054. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2055. if masterIed != nil {
  2056. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2057. } else {
  2058. if dealFromIed[findIedName] == 0 {
  2059. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2060. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2061. //检查未通过
  2062. scdNodeRule.AppendFcdaCheckResult(r)
  2063. }
  2064. dealFromIed[findIedName] = 1
  2065. }
  2066. }
  2067. if strings.HasPrefix(findIedName, toiedtype) {
  2068. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2069. }
  2070. }
  2071. if len(tmpFromAreaIeds) == 0 {
  2072. continue
  2073. }
  2074. if len(tmpToAreaIeds) == 0 {
  2075. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  2076. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2077. //检查未通过
  2078. scdNodeRule.AppendFcdaCheckResult(r)
  2079. continue
  2080. }
  2081. toIedname := ""
  2082. for _, row2 := range tmpFromAreaIeds {
  2083. findIedName = tools.IsEmpty(row2["ied_name"])
  2084. hasToIedRef := false
  2085. hasToIed := false
  2086. for _, row3 := range tmpToAreaIeds {
  2087. toIedname = tools.IsEmpty(row3["ied_name"])
  2088. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  2089. if masterIed != nil {
  2090. hasToIed = true
  2091. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2092. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2093. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2094. if inout != nil {
  2095. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2096. for _, ieditem := range outiedlist {
  2097. outiedname := ieditem["ref_ied_name"].(string)
  2098. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2099. hasToIedRef = true
  2100. break
  2101. }
  2102. }
  2103. }
  2104. if !hasToIedRef {
  2105. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2106. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2107. //检查未通过
  2108. scdNodeRule.AppendFcdaCheckResult(r)
  2109. }
  2110. }
  2111. }
  2112. if !hasToIed {
  2113. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2114. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2115. //检查未通过
  2116. scdNodeRule.AppendFcdaCheckResult(r)
  2117. }
  2118. }
  2119. }
  2120. }
  2121. //线路间隔装置关系检查
  2122. 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) {
  2123. modelidInt, _ := strconv.Atoi(modelid)
  2124. //获取装置分组信息
  2125. bgm := new(SysCheckModelIedtypeGroupMgr)
  2126. bgm.Model = T_data_model_iedtype_group{ModelId: modelidInt}
  2127. groupList := bgm.List()
  2128. plIed := c.getIedTypeCode(modelidInt, "PL")
  2129. if v, h := groupList[plIed]; h {
  2130. //装置如果是分组成员装置
  2131. plIed = v
  2132. }
  2133. masterIed := new(node_attr.NIED)
  2134. findIedName := ""
  2135. for _, row2 := range area_ieds {
  2136. findIedName = tools.IsEmpty(row2["ied_name"])
  2137. if strings.HasPrefix(findIedName, plIed) {
  2138. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2139. break
  2140. }
  2141. }
  2142. if masterIed == nil {
  2143. return
  2144. }
  2145. logger.Logger.Debug(fmt.Sprintf("开始分析模型%d的线路间隔关系", modelidInt))
  2146. dealFromIed := map[string]int{}
  2147. for _, row := range ied_refs {
  2148. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  2149. toiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"]))
  2150. reftype := tools.IsEmpty(row["in_type"])
  2151. tmpFromAreaIeds := []orm.Params{}
  2152. tmpToAreaIeds := []orm.Params{}
  2153. for _, row2 := range area_ieds {
  2154. findIedName = tools.IsEmpty(row2["ied_name"])
  2155. if strings.HasPrefix(findIedName, fromiedtype) {
  2156. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2157. if masterIed != nil {
  2158. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2159. } else {
  2160. if dealFromIed[findIedName] == 0 {
  2161. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2162. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2163. "ied_name": findIedName,
  2164. "ied_desc": "",
  2165. "out_ied_name": "",
  2166. "out_ied_desc": "",
  2167. "fcda_desc": "",
  2168. "fcda_addr": "",
  2169. "out_fcda_desc": "",
  2170. "out_fcda_addr": "",
  2171. "error_type": "9",
  2172. }
  2173. //检查未通过
  2174. scdNodeRule.AppendFcdaCheckResult(r)
  2175. }
  2176. dealFromIed[findIedName] = 1
  2177. }
  2178. }
  2179. if strings.HasPrefix(findIedName, toiedtype) {
  2180. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2181. }
  2182. }
  2183. if len(tmpFromAreaIeds) == 0 {
  2184. continue
  2185. }
  2186. if len(tmpToAreaIeds) == 0 {
  2187. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  2188. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2189. //检查未通过
  2190. scdNodeRule.AppendFcdaCheckResult(r)
  2191. continue
  2192. }
  2193. toIedname := ""
  2194. for _, row2 := range tmpFromAreaIeds {
  2195. findIedName = tools.IsEmpty(row2["ied_name"])
  2196. hasToIedRef := false
  2197. hasToIed := false
  2198. for _, row3 := range tmpToAreaIeds {
  2199. toIedname = tools.IsEmpty(row3["ied_name"])
  2200. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  2201. if masterIed != nil {
  2202. hasToIed = true
  2203. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2204. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2205. //logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2206. if inout != nil {
  2207. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2208. for _, ieditem := range outiedlist {
  2209. outiedname := ieditem["ref_ied_name"].(string)
  2210. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2211. hasToIedRef = true
  2212. break
  2213. }
  2214. }
  2215. }
  2216. if !hasToIedRef {
  2217. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2218. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2219. "ied_name": findIedName,
  2220. "ied_desc": "",
  2221. "out_ied_name": toIedname,
  2222. "out_ied_desc": "",
  2223. "fcda_desc": "",
  2224. "fcda_addr": "",
  2225. "out_fcda_desc": "",
  2226. "out_fcda_addr": "",
  2227. "error_type": "9",
  2228. }
  2229. //检查未通过
  2230. scdNodeRule.AppendFcdaCheckResult(r)
  2231. }
  2232. }
  2233. }
  2234. if !hasToIed {
  2235. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2236. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2237. "ied_name": findIedName,
  2238. "ied_desc": "",
  2239. "out_ied_name": toIedname,
  2240. "out_ied_desc": "",
  2241. "fcda_desc": "",
  2242. "fcda_addr": "",
  2243. "out_fcda_desc": "",
  2244. "out_fcda_addr": "",
  2245. "error_type": "9",
  2246. }
  2247. //检查未通过
  2248. scdNodeRule.AppendFcdaCheckResult(r)
  2249. }
  2250. }
  2251. }
  2252. }
  2253. //变压器间隔装置关系检查
  2254. 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) {
  2255. masterIed := new(node_attr.NIED)
  2256. findIedName := ""
  2257. modelidInt, _ := strconv.Atoi(modelid)
  2258. ptIed := c.getIedTypeCode(modelidInt, "PT")
  2259. for _, row2 := range area_ieds {
  2260. findIedName = tools.IsEmpty(row2["ied_name"])
  2261. if strings.HasPrefix(findIedName, ptIed) {
  2262. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2263. break
  2264. }
  2265. }
  2266. if masterIed == nil {
  2267. return
  2268. }
  2269. scdParseMgr := new(ScdParse)
  2270. dealFromIed := map[string]int{}
  2271. for _, row := range ied_refs {
  2272. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  2273. fromiedtype = strings.Split(fromiedtype, "#")[0] //去除后面的电压级别标识
  2274. toiedtype := strings.Split(c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"])), "#")[0] //去除后面的电压级别标识
  2275. reftype := tools.IsEmpty(row["in_type"])
  2276. tmpFromAreaIeds := []orm.Params{}
  2277. tmpToAreaIeds := []orm.Params{}
  2278. for _, row2 := range area_ieds {
  2279. findIedName = tools.IsEmpty(row2["ied_name"])
  2280. if strings.HasPrefix(findIedName, fromiedtype) {
  2281. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2282. if masterIed != nil {
  2283. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2284. } else {
  2285. if dealFromIed[findIedName] == 0 {
  2286. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2287. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2288. "ied_name": findIedName,
  2289. "ied_desc": "",
  2290. "out_ied_name": "",
  2291. "out_ied_desc": "",
  2292. "fcda_desc": "",
  2293. "fcda_addr": "",
  2294. "out_fcda_desc": "",
  2295. "out_fcda_addr": "",
  2296. "error_type": "9",
  2297. }
  2298. //检查未通过
  2299. scdNodeRule.AppendFcdaCheckResult(r)
  2300. }
  2301. dealFromIed[findIedName] = 1
  2302. }
  2303. }
  2304. if strings.HasPrefix(findIedName, toiedtype) {
  2305. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2306. }
  2307. }
  2308. if len(tmpFromAreaIeds) == 0 {
  2309. continue
  2310. }
  2311. if len(tmpToAreaIeds) == 0 {
  2312. logger.Logger.Debug(fmt.Sprintf("缺失类型关联装置 :%+v", row))
  2313. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的%s信号装置", area_name, toiedtype, reftype)
  2314. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2315. "ied_name": findIedName,
  2316. "ied_desc": "",
  2317. "out_ied_name": "",
  2318. "out_ied_desc": "",
  2319. "fcda_desc": "",
  2320. "fcda_addr": "",
  2321. "out_fcda_desc": "",
  2322. "out_fcda_addr": "",
  2323. "error_type": "9",
  2324. }
  2325. //检查未通过
  2326. scdNodeRule.AppendFcdaCheckResult(r)
  2327. continue
  2328. }
  2329. toIedname := ""
  2330. for _, row2 := range tmpFromAreaIeds {
  2331. findIedName = tools.IsEmpty(row2["ied_name"])
  2332. hasToIedRef := false
  2333. hasToIed := false
  2334. t1 := fromiedtype + "->" + toiedtype
  2335. volLevel := "" //电压等级
  2336. 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" {
  2337. ps := scdParseMgr.ParseIedName(findIedName)
  2338. volLevel = ps[3] + ps[4]
  2339. }
  2340. hasSameVolIed := false
  2341. for _, row3 := range tmpToAreaIeds {
  2342. toIedname = tools.IsEmpty(row3["ied_name"])
  2343. if volLevel != "" {
  2344. ps := scdParseMgr.ParseIedName(toIedname)
  2345. if volLevel != ps[3]+ps[4] {
  2346. //排除不是同一电压等级的装置
  2347. continue
  2348. }
  2349. hasSameVolIed = true
  2350. }
  2351. if scdNodeMgr.GetIed(scdXmlObj, "", toIedname) != nil {
  2352. hasToIed = true
  2353. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2354. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2355. //logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2356. if inout != nil {
  2357. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2358. for _, ieditem := range outiedlist {
  2359. outiedname := ieditem["ref_ied_name"].(string)
  2360. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2361. hasToIedRef = true
  2362. break
  2363. }
  2364. }
  2365. }
  2366. if !hasToIedRef {
  2367. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2368. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2369. "ied_name": findIedName,
  2370. "ied_desc": "",
  2371. "out_ied_name": toIedname,
  2372. "out_ied_desc": "",
  2373. "fcda_desc": "",
  2374. "fcda_addr": "",
  2375. "out_fcda_desc": "",
  2376. "out_fcda_addr": "",
  2377. "error_type": "9",
  2378. }
  2379. //检查未通过
  2380. scdNodeRule.AppendFcdaCheckResult(r)
  2381. }
  2382. }
  2383. if hasSameVolIed {
  2384. break
  2385. }
  2386. }
  2387. if toiedtype != ptIed {
  2388. if volLevel != "" && !hasSameVolIed {
  2389. parse_result := fmt.Sprintf("间隔%s的装置%s缺失同电压等级的关联类型%s装置", area_name, findIedName, toiedtype)
  2390. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2391. "ied_name": findIedName,
  2392. "ied_desc": "",
  2393. "out_ied_name": "",
  2394. "out_ied_desc": "",
  2395. "fcda_desc": "",
  2396. "fcda_addr": "",
  2397. "out_fcda_desc": "",
  2398. "out_fcda_addr": "",
  2399. "error_type": "9",
  2400. }
  2401. //检查未通过
  2402. scdNodeRule.AppendFcdaCheckResult(r)
  2403. } else if !hasToIed {
  2404. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2405. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2406. "ied_name": findIedName,
  2407. "ied_desc": "",
  2408. "out_ied_name": toIedname,
  2409. "out_ied_desc": "",
  2410. "fcda_desc": "",
  2411. "fcda_addr": "",
  2412. "out_fcda_desc": "",
  2413. "out_fcda_addr": "",
  2414. "error_type": "9",
  2415. }
  2416. //检查未通过
  2417. scdNodeRule.AppendFcdaCheckResult(r)
  2418. }
  2419. }
  2420. }
  2421. }
  2422. }
  2423. //根据参考ied name找出应该关联PM装置
  2424. //abcode:套别标识代码。可选。不指定时将自动从iedtype识别
  2425. func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params, abcode ...string) string {
  2426. //如果只有一个PM装置,则直接返回该 装置
  2427. pmLst := []string{}
  2428. for n, _ := range ieds {
  2429. if strings.HasPrefix(n, "PM"+iednameParts[3]+iednameParts[4]) {
  2430. pmLst = append(pmLst, n)
  2431. }
  2432. }
  2433. if len(pmLst) == 1 {
  2434. return pmLst[0]
  2435. }
  2436. ab := ""
  2437. if len(abcode) > 0 {
  2438. ab = abcode[0]
  2439. }
  2440. //暴力匹配
  2441. for _, n := range pmLst {
  2442. if ab != "" {
  2443. //优先完全匹配指定套别
  2444. if strings.HasSuffix(n, ab) {
  2445. return n
  2446. }
  2447. continue
  2448. }
  2449. if strings.HasSuffix(n, iednameParts[7]) {
  2450. return n
  2451. }
  2452. }
  2453. return ""
  2454. }
  2455. //根据参考ied name找出应该关联MM装置
  2456. func (c *CheckAreaMgr) getMMName(iednameParts []string, ieds map[string]orm.Params, ab string) string {
  2457. mmLst := []string{}
  2458. for n, _ := range ieds {
  2459. if strings.HasPrefix(n, "MM"+iednameParts[3]+iednameParts[4]) {
  2460. mmLst = append(mmLst, n)
  2461. }
  2462. }
  2463. if len(mmLst) == 1 {
  2464. return mmLst[0]
  2465. }
  2466. for _, n := range mmLst {
  2467. if ab != "" && strings.HasSuffix(n, ab) {
  2468. return n
  2469. }
  2470. if ab == "" && strings.HasSuffix(n, iednameParts[5]+iednameParts[6]) {
  2471. return n
  2472. }
  2473. }
  2474. //理论上的装置名称
  2475. return "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + ab
  2476. }
  2477. //获取装置编码中的套别代码(A、B..)
  2478. func (c *CheckAreaMgr) getIedTypeABCode(iedtype string) string {
  2479. if strings.Index(iedtype, "-") > 0 {
  2480. return strings.Split(iedtype, "-")[1]
  2481. }
  2482. return ""
  2483. }
  2484. //根据当前设备列表,分析出电压等级(高、中、低)的设备列表
  2485. // CT测控、IT智能终端、MT合并单元需要判断是否是本体装置,是则将其归为主变高压侧
  2486. //iedtype:装置编码
  2487. //ieds:装置筛选范围列表
  2488. //vollevel:电压等级代码。H:高压 M:中压 L:低压
  2489. //abcode:套别标识代码。可选。不指定时将自动从iedtype识别
  2490. func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string, abcode ...string) (hightLst, middleLst, lowLst []orm.Params) {
  2491. tmpLst := map[string][]orm.Params{}
  2492. for _, v := range vollevel {
  2493. tmpLst[v] = []orm.Params{}
  2494. }
  2495. ab := ""
  2496. if len(abcode) > 0 {
  2497. ab = abcode[0]
  2498. }
  2499. if strings.Index(iedtype, "-") > 0 {
  2500. //去除套别标识
  2501. iedtype = strings.Split(iedtype, "-")[0]
  2502. if ab == "" {
  2503. ab = strings.Split(iedtype, "-")[1]
  2504. }
  2505. }
  2506. it := strings.Split(iedtype, "#")
  2507. scdParseMgr := new(ScdParse)
  2508. for _, row := range ieds {
  2509. pl_iedname := tools.IsEmpty(row["ied_name"])
  2510. if pl_iedname[0:len(it[0])] != it[0] {
  2511. continue
  2512. }
  2513. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  2514. if ab != "" && iednameParts[7] != ab {
  2515. //指定了套别时,装置套别必须与指定套别完全相同
  2516. continue
  2517. }
  2518. volvalue := iednameParts[3] + iednameParts[4]
  2519. if tmpLst[volvalue] == nil {
  2520. tmpLst[volvalue] = []orm.Params{row}
  2521. } else {
  2522. tmpLst[volvalue] = append(tmpLst[volvalue], row)
  2523. }
  2524. }
  2525. if len(it) > 1 {
  2526. if it[1] == "H" {
  2527. return tmpLst[vollevel["hight"]], []orm.Params{}, []orm.Params{}
  2528. }
  2529. if it[1] == "M" {
  2530. return []orm.Params{}, tmpLst[vollevel["middle"]], []orm.Params{}
  2531. }
  2532. if it[1] == "L" {
  2533. return []orm.Params{}, []orm.Params{}, tmpLst[vollevel["low"]]
  2534. }
  2535. }
  2536. return tmpLst[vollevel["hight"]], tmpLst[vollevel["middle"]], tmpLst[vollevel["low"]]
  2537. }
  2538. func (c *CheckAreaMgr) GetCheckResult(scdid int64) ([]orm.Params, error) {
  2539. db := orm.NewOrm()
  2540. rowset := []orm.Params{}
  2541. 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"
  2542. _, err := db.Raw(sql, scdid).Values(&rowset)
  2543. return rowset, err
  2544. }