checktools_area.go 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544
  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 from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
  884. typeMappingMgr := new(SysCheckModelIedtypeMappingMgr)
  885. pmCode := c.getIedTypeCode(modelid, "PM")
  886. //循环处理关联关系
  887. for to_ied_type2, refrow := range funclist {
  888. logger.Logger.Debug(fmt.Sprintf("================正在检查类型%s关系===============", to_ied_type2))
  889. ts := strings.Split(to_ied_type2, ",")
  890. //从间隔中获取当前同类型的信号接收装置
  891. ied_type := c.getIedTypeCode(modelid, ts[0])
  892. if v, h := groupList[ied_type]; h {
  893. ied_type = typeMappingMgr.GetMappingType(modelid, v)
  894. }
  895. abCode := c.getIedTypeABCode(ied_type)
  896. ied_type, vol := getIedTypeAndVolCode(ied_type)
  897. isReceivePm := strings.HasPrefix(ied_type, pmCode) //接收装置是Pm装置
  898. iedlst := filterAreaIeds(ied_type, vol, s1, abCode, isReceivePm)
  899. logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s与%s的装置(%+v)端子关系", ied_type, vol, ts[1], iedlst))
  900. //从间隔中获取当前信号输出装置
  901. outiedlist := map[string]orm.Params{}
  902. fromiedcode := c.getIedTypeCode(modelid, ts[1])
  903. if v, h := groupList[fromiedcode]; h {
  904. fromiedcode = typeMappingMgr.GetMappingType(modelid, v)
  905. }
  906. fromAbCode := c.getIedTypeABCode(fromiedcode)
  907. from_ied_type, vol2 := getIedTypeAndVolCode(fromiedcode)
  908. isOutPm := strings.HasPrefix(from_ied_type, pmCode) //输出装置是PM装置
  909. outiedlist2 := filterAreaIeds(from_ied_type, vol2, s1, fromAbCode, isOutPm)
  910. for _, iedrow := range outiedlist2 {
  911. iedname := tools.IsEmpty(iedrow["ied_name"])
  912. outiedlist[iedname] = iedrow
  913. }
  914. if len(outiedlist) == 0 {
  915. logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s%s未从类型%s%s的任何电压等级%s装置接收信号", ied_type, vol, abCode, from_ied_type, fromAbCode, vol2))
  916. continue
  917. }
  918. logger.Logger.Debug(fmt.Sprintf("当前装置类型:%s%s的装置(%+v)与类型%s#%s%s存在以下信号输出装置:%+v", ied_type, abCode, iedlst, from_ied_type, fromAbCode, vol2, outiedlist))
  919. //logger.Logger.Debug(fmt.Sprintf("设计端子关联关系:%+v", refrow))
  920. for _, ied := range iedlst {
  921. iedname := tools.IsEmpty(ied["ied_name"])
  922. iedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, iedname)
  923. iedObjDesc := ""
  924. if iedObj != nil {
  925. iedObjDesc = iedObj.Desc
  926. } else {
  927. logger.Logger.Error(fmt.Sprintf("信号接收装置%s未找到!", iedname))
  928. continue
  929. }
  930. //遥信端子列表:仅根据scd实际配置检查其双方端子的doi名称是否相同
  931. scdMgr := new(ScdMgr)
  932. yx, h := isLoadYxIed[iedname]
  933. if !h {
  934. yx = scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
  935. isLoadYxIed[iedname] = yx
  936. }
  937. yxAddrMap := map[string]int{}
  938. for sg, _ := range yx {
  939. key := fmt.Sprintf("%s%s%s%s%s%s%s", sg.IedName, sg.IntAddr, sg.LdInst, sg.Prefix, sg.LnClass, sg.LnInst, sg.DoName)
  940. yxAddrMap[key] = 1
  941. }
  942. //所有端子列表
  943. extreflist := isLoadExtref[iedname]
  944. if extreflist == nil {
  945. extreflist = getIedExtRefs(iedname)
  946. }
  947. for outiedname, outied := range outiedlist {
  948. if iedname == outiedname {
  949. continue
  950. }
  951. logger.Logger.Debug(fmt.Sprintf("正在匹配装置%s与%s的端子关联关系", iedname, outiedname))
  952. outIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, outiedname)
  953. outIedObjDesc := ""
  954. if outIedObj == nil {
  955. logger.Logger.Error(fmt.Sprintf("信号输出装置%s未找到!", outiedname))
  956. } else {
  957. outIedObjDesc = outIedObj.Desc
  958. }
  959. if iedObj == nil && outIedObj == nil {
  960. continue
  961. }
  962. //outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
  963. //是否设置的端子编号
  964. noText := tools.IsEmpty(ied["ied_no"])
  965. if noText == "" {
  966. noText = tools.IsEmpty(outied["ied_no"])
  967. }
  968. //检查是否有错误和缺失的端子
  969. for _, r := range refrow {
  970. extref_name := tools.IsEmpty(r["to_fcda_name"])
  971. fcda_name := tools.IsEmpty(r["from_fcda_name"])
  972. extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
  973. fcda_name_exp := tools.IsEmpty(r["from_fcda_match_exp"])
  974. funcName := tools.IsEmpty(r["to_func_name"])
  975. //端子编号处理
  976. if strings.Index(extref_name_exp, "{no}") > -1 {
  977. extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", noText)
  978. }
  979. if strings.Index(fcda_name_exp, "{no}") > -1 {
  980. fcda_name_exp = strings.ReplaceAll(fcda_name_exp, "{no}", noText)
  981. }
  982. funcExist := false //判断接收端设计的端子是否存在
  983. extrefObj := new(node_attr.NExtRef)
  984. fcda2Exist := false
  985. isYx := false
  986. for desc, item := range extreflist {
  987. if item.IedName != outiedname {
  988. continue
  989. }
  990. //判断是否是遥信端子
  991. /*
  992. 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 {
  993. isYx = true
  994. break
  995. }
  996. */
  997. //logger.Logger.Debug(fmt.Sprintf("接收装置%s的设计端子%s匹配SCD ExtRef DO端子%s", iedname, extref_name_exp, desc))
  998. macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, desc)
  999. if macthResult {
  1000. funcExist = true
  1001. extrefObj = item
  1002. extref_name = desc //实际的端子名称
  1003. break
  1004. }
  1005. }
  1006. if isYx {
  1007. //遥信端子不处理
  1008. continue
  1009. }
  1010. if funcExist {
  1011. //判断输出端端子是否存在
  1012. doi, _ := scdNodeRule.IedFcdaExist(extrefObj.IedName, extrefObj.LdInst, extrefObj.LnClass, extrefObj.LnInst, extrefObj.Prefix, extrefObj.DoName, "")
  1013. if doi != nil {
  1014. daname := ""
  1015. if extrefObj.DaName != "" {
  1016. daname = "." + extrefObj.DaName
  1017. }
  1018. fcda2Exist = true
  1019. fcda_name = doi.(*node_attr.NDOI).Desc //实际的端子名称
  1020. if strings.Index(funcName, "遥信") > -1 {
  1021. //2端端子名称需要完全相同
  1022. if extref_name != fcda_name {
  1023. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s关联错误:端子名称不相同", area_name, iedname, extref_name, outiedname, fcda_name)
  1024. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1025. "ied_name": iedname,
  1026. "ied_desc": iedObj.Desc,
  1027. "out_ied_name": outiedname,
  1028. "out_ied_desc": outIedObjDesc,
  1029. "fcda_desc": extref_name,
  1030. "fcda_addr": extrefObj.IntAddr,
  1031. "out_fcda_desc": fcda_name,
  1032. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
  1033. "error_type": "2",
  1034. }
  1035. //检查未通过
  1036. scdNodeRule.AppendFcdaCheckResult(re)
  1037. } else {
  1038. //判断是否是双点或单点遥信端子
  1039. extrefDoi := scdNodeRule.IedIntAddrExist(iedname, extrefObj.IntAddr)
  1040. extrefDoiCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, extrefDoi.(*node_attr.NDOI))
  1041. fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, doi.(*node_attr.NDOI))
  1042. if extrefDoiCdcCode != fcdaCdcCode {
  1043. //错误:cdc类型不一致
  1044. 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)
  1045. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1046. "ied_name": iedname,
  1047. "ied_desc": iedObj.Desc,
  1048. "out_ied_name": outiedname,
  1049. "out_ied_desc": outIedObjDesc,
  1050. "fcda_desc": extref_name,
  1051. "fcda_addr": extrefObj.IntAddr,
  1052. "out_fcda_desc": fcda_name,
  1053. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extrefObj.LdInst, extrefObj.Prefix, extrefObj.LnClass, extrefObj.LnInst, extrefObj.DoName, daname),
  1054. "error_type": "2",
  1055. }
  1056. //检查未通过
  1057. scdNodeRule.AppendFcdaCheckResult(re)
  1058. }
  1059. }
  1060. continue
  1061. }
  1062. macthResult, _ := tools.RexGroupTestMatch(fcda_name_exp, fcda_name)
  1063. if !macthResult {
  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. }
  1079. }
  1080. }
  1081. if !funcExist {
  1082. parse_result := fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, iedname, extref_name)
  1083. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1084. "ied_name": iedname,
  1085. "ied_desc": iedObjDesc,
  1086. "out_ied_name": "",
  1087. "out_ied_desc": "",
  1088. "fcda_desc": extref_name,
  1089. "fcda_addr": "",
  1090. "out_fcda_desc": "",
  1091. "out_fcda_addr": "",
  1092. "error_type": "3",
  1093. }
  1094. //检查未通过
  1095. scdNodeRule.AppendFcdaCheckResult(re)
  1096. } else if !fcda2Exist {
  1097. //fcda2Exist为false表示实际的端子from ied不是当前设计的ied
  1098. parse_result := fmt.Sprintf("间隔%s下%s的输入装置%s缺失端子%s", area_name, iedname, outiedname, fcda_name)
  1099. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1100. "ied_name": iedname,
  1101. "ied_desc": iedObjDesc,
  1102. "out_ied_name": outiedname,
  1103. "out_ied_desc": outIedObjDesc,
  1104. "fcda_desc": extref_name,
  1105. "fcda_addr": extrefObj.IntAddr,
  1106. "out_fcda_desc": fcda_name,
  1107. "out_fcda_addr": "",
  1108. "error_type": "3",
  1109. }
  1110. //检查未通过
  1111. scdNodeRule.AppendFcdaCheckResult(re)
  1112. }
  1113. }
  1114. //检查是否有多余(SCD中有不存在于设计中)的端子
  1115. for extrefdesc, r := range extreflist { //scd中的端子关系
  1116. //判断是否是当前输入装置和遥信端子
  1117. 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 {
  1118. continue
  1119. }
  1120. extref_name := ""
  1121. fcda_name := ""
  1122. isHave := false
  1123. for _, r1 := range refrow { //设计的端子关系
  1124. extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
  1125. //端子编号处理
  1126. if strings.Index(extref_name_exp, "{no}") > -1 {
  1127. extref_name_exp = strings.ReplaceAll(extref_name_exp, "{no}", noText)
  1128. }
  1129. macthResult, _ := tools.RexGroupTestMatch(extref_name_exp, extrefdesc)
  1130. if extrefdesc == extref_name_exp || macthResult {
  1131. //端子存在
  1132. isHave = true
  1133. break
  1134. }
  1135. }
  1136. if !isHave {
  1137. daname := ""
  1138. if r.DaName != "" {
  1139. daname = "." + r.DaName
  1140. }
  1141. doi := scdNodeRule.IedIntAddrExist(iedname, r.IntAddr)
  1142. if doi != nil {
  1143. extref_name = doi.(*node_attr.NDOI).Desc
  1144. }
  1145. doi, _ = scdNodeRule.IedFcdaExist(r.IedName, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
  1146. if doi != nil {
  1147. fcda_name = doi.(*node_attr.NDOI).Desc
  1148. }
  1149. tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, r.IedName)
  1150. parse_result := fmt.Sprintf("间隔%s下装置(%s)的端子%s在设计中不存在", area_name, iedname, extref_name)
  1151. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1152. "ied_name": iedname,
  1153. "ied_desc": iedObj.Desc,
  1154. "out_ied_name": r.IedName,
  1155. "out_ied_desc": tmpIedObj.Desc,
  1156. "fcda_desc": extref_name,
  1157. "fcda_addr": r.IntAddr,
  1158. "out_fcda_desc": fcda_name,
  1159. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName, daname),
  1160. "error_type": "1",
  1161. }
  1162. //检查未通过
  1163. scdNodeRule.AppendFcdaCheckResult(re)
  1164. }
  1165. }
  1166. }
  1167. //判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
  1168. //遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致以及单双点类型是否相同,以及是否有缺失和多余的遥信端子
  1169. /*
  1170. if len(yx) > 0 && isDealYxIed[iedname] == 0 {
  1171. //logger.Logger.Debug(fmt.Sprintf("=============正在处理装置%s遥信端子数:%d %+v", iedname, len(yx), isDealYxIed))
  1172. isDealYxIed[iedname] = 1
  1173. for extref, doiinfo := range yx {
  1174. doiDesc := doiinfo[0]
  1175. doiCdc := doiinfo[1]
  1176. daname := ""
  1177. if extref.DaName != "" {
  1178. daname = "." + extref.DaName
  1179. }
  1180. //获取输出端端子名称
  1181. outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
  1182. tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, extref.IedName)
  1183. if tmpIedObj == nil || outFcdaDoi == nil {
  1184. //端子缺失
  1185. tmpIedName := ""
  1186. tmpIedDesc := ""
  1187. if tmpIedObj != nil {
  1188. tmpIedName = tmpIedObj.Name
  1189. tmpIedDesc = tmpIedObj.Desc
  1190. }
  1191. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s的关联端子不存在", area_name, iedname, doiDesc)
  1192. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1193. "ied_name": iedname,
  1194. "ied_desc": iedObj.Desc,
  1195. "out_ied_name": tmpIedName,
  1196. "out_ied_desc": tmpIedDesc,
  1197. "fcda_desc": doiDesc,
  1198. "fcda_addr": extref.IntAddr,
  1199. "out_fcda_desc": "",
  1200. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1201. "error_type": "3",
  1202. }
  1203. //检查未通过
  1204. scdNodeRule.AppendFcdaCheckResult(re)
  1205. continue
  1206. }
  1207. if doiCdc != "" && (!YaoXinDBType[doiCdc] || !YaoXinSiType[doiCdc]) {
  1208. //判断是否是双点或单点遥信端子
  1209. fcdaCdcCode := new(ScdMgr).GetDoiCdcInfo(scdXmlObj, c.ScdId, outFcdaDoi.(*node_attr.NDOI))
  1210. if doiCdc != fcdaCdcCode {
  1211. //错误:cdc类型不一致
  1212. 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)
  1213. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1214. "ied_name": iedname,
  1215. "ied_desc": iedObj.Desc,
  1216. "out_ied_name": tmpIedObj.Name,
  1217. "out_ied_desc": tmpIedObj.Desc,
  1218. "fcda_desc": doiDesc,
  1219. "fcda_addr": extref.IntAddr,
  1220. "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
  1221. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1222. "error_type": "2",
  1223. }
  1224. //检查未通过
  1225. scdNodeRule.AppendFcdaCheckResult(re)
  1226. continue
  1227. }
  1228. }
  1229. if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
  1230. //关联错误
  1231. parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc)
  1232. re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  1233. "ied_name": iedname,
  1234. "ied_desc": iedObj.Desc,
  1235. "out_ied_name": tmpIedObj.Name,
  1236. "out_ied_desc": tmpIedObj.Desc,
  1237. "fcda_desc": doiDesc,
  1238. "fcda_addr": extref.IntAddr,
  1239. "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
  1240. "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
  1241. "error_type": "2",
  1242. }
  1243. //检查未通过
  1244. scdNodeRule.AppendFcdaCheckResult(re)
  1245. }
  1246. }
  1247. }
  1248. */
  1249. yxAddrMap = nil
  1250. extreflist = nil
  1251. }
  1252. }
  1253. }
  1254. isLoadYxIed = nil
  1255. scdNodeRule.CheckFinish()
  1256. scdNodeRule.Flush()
  1257. return nil
  1258. }
  1259. //解析模型间隔。根据模型定义解析出间隔中的装置
  1260. func (c *CheckAreaMgr) ParseModelArea() {
  1261. c.Init(c.ScdId)
  1262. key := fmt.Sprintf("%d-checkinfo", c.ScdId)
  1263. areaCheckInfo.Delete(key)
  1264. // 取得当前scd所有ied及名称解析结果
  1265. dbo := orm.NewOrm()
  1266. 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"
  1267. iedlst := []orm.Params{}
  1268. _, err := dbo.Raw(sql, c.ScdId).Values(&iedlst)
  1269. if err != nil {
  1270. logger.Logger.Error(err)
  1271. return
  1272. }
  1273. logger.Logger.Debug(fmt.Sprintf("=====总装置数:%d", len(iedlst)))
  1274. iedMap := map[string]orm.Params{}
  1275. for _, r := range iedlst {
  1276. iedMap[tools.IsEmpty(r["ied_name"])] = r
  1277. }
  1278. //先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
  1279. HasAreaJ := false
  1280. for _, row := range c.CheckModelList {
  1281. areaCode := tools.IsEmpty(row["area_type_code"])
  1282. if areaCode == "J" {
  1283. HasAreaJ = true
  1284. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  1285. //modelname := tools.IsEmpty(row["model_name"])
  1286. iedtypes := tools.IsEmpty(row["ied_types"])
  1287. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1288. mapptype.Model = T_data_model_iedtype_mapping{ModelId: modelid}
  1289. mappresult := mapptype.List()
  1290. if len(mappresult) > 0 {
  1291. tmp := []string{}
  1292. for _, r := range strings.Split(iedtypes, ",") {
  1293. if mappresult[r] != "" {
  1294. tmp = append(tmp, mappresult[r])
  1295. } else {
  1296. tmp = append(tmp, r)
  1297. }
  1298. }
  1299. iedtypes = strings.Join(tmp, ",")
  1300. }
  1301. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  1302. c.pJ(modelid, volcode, iedtypes, iedMap, "PE")
  1303. c.pJ(modelid, volcode, iedtypes, iedMap, "PJ")
  1304. c.pJ(modelid, volcode, iedtypes, iedMap, "PK")
  1305. c.pJ(modelid, volcode, iedtypes, iedMap, "PF")
  1306. }
  1307. }
  1308. for _, row := range c.CheckModelList {
  1309. //逐一分析模型定义
  1310. modelid, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  1311. modelname := tools.IsEmpty(row["model_name"])
  1312. iedtypes := tools.IsEmpty(row["ied_types"])
  1313. //模型对应的间隔代码
  1314. /*
  1315. S 站用变压器
  1316. C 电容器
  1317. B 断路器
  1318. K 母分
  1319. J 母联
  1320. M 母线
  1321. X 电抗器
  1322. L 线路
  1323. T 主变压器
  1324. */
  1325. areaCode := tools.IsEmpty(row["area_type_code"])
  1326. //模型对应的电压等级
  1327. //10:10KV 35:35KV 66:66KV 11:110KV 22:220KV 50:500KV 75:750KV 33:330KV T0:1000KV
  1328. volcode := strings.ReplaceAll(tools.IsEmpty(row["vol_code"]), "v_level_", "")
  1329. if modelname == "" || iedtypes == "" {
  1330. continue
  1331. }
  1332. //母联间隔已经提前分析,如果没有母联间隔时,主变间隔中不包含母联终端装置
  1333. if areaCode == "J" {
  1334. continue
  1335. }
  1336. //获取模型中的自定义装置类型编码
  1337. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1338. mapptype.Model = T_data_model_iedtype_mapping{ModelId: modelid}
  1339. mappresult := mapptype.List()
  1340. if len(mappresult) > 0 {
  1341. tmp := []string{}
  1342. for _, r := range strings.Split(iedtypes, ",") {
  1343. if mappresult[r] != "" {
  1344. tmp = append(tmp, mappresult[r])
  1345. } else {
  1346. tmp = append(tmp, r)
  1347. }
  1348. }
  1349. iedtypes = strings.Join(tmp, ",")
  1350. }
  1351. //获取模型内中装备关系定义
  1352. //主变间隔分析:需要查站内该电压等级下的高中低压侧装置或者高低压装置组成一个间隔,以主变保护装置(PT)为起始
  1353. if areaCode == "T" {
  1354. c.pT(modelid, volcode, iedtypes, iedMap, HasAreaJ)
  1355. }
  1356. //线路保护间隔分析:以线路保护测控装置(PL)为开始分析
  1357. if areaCode == "L" {
  1358. c.pL(modelid, volcode, iedtypes, iedMap)
  1359. }
  1360. //母线间隔分析:PM
  1361. if areaCode == "M" {
  1362. c.pM(modelid, volcode, iedtypes, iedMap)
  1363. }
  1364. }
  1365. }
  1366. //根据默认装置类型获取其类型编码。如果没有自定义编码,则返回默认编码。返回编码时已自动去除套别标识
  1367. func (c *CheckAreaMgr) getIedTypeCode(modelid int, iedtype string) string {
  1368. mapptype := new(SysCheckModelIedtypeMappingMgr)
  1369. mappresult := mapptype.GetMappingType(modelid, iedtype)
  1370. ptCode := iedtype
  1371. if mappresult != "" {
  1372. ptCode = mappresult //自定义主变保护编码
  1373. }
  1374. return strings.Split(ptCode, "-")[0]
  1375. }
  1376. //变压器间隔分析
  1377. func (c *CheckAreaMgr) pT(modelid int, vol, iedtypes string, ieds map[string]orm.Params, HasAreaJ bool) {
  1378. scdParseMgr := new(ScdParse)
  1379. scdNodeMgr := new(ScdNode)
  1380. db := orm.NewOrm()
  1381. //获取装置分组信息
  1382. bgm := new(SysCheckModelIedtypeGroupMgr)
  1383. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1384. groupList := bgm.List()
  1385. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1386. //获取当前站的各电压等级
  1387. volRows := []orm.Params{}
  1388. _, 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)
  1389. if err != nil {
  1390. logger.Logger.Error(err)
  1391. return
  1392. }
  1393. if len(volRows) == 0 {
  1394. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  1395. return
  1396. }
  1397. volMap := map[string]string{}
  1398. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  1399. if len(volRows) == 2 {
  1400. volMap["middle"] = ""
  1401. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  1402. } else {
  1403. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  1404. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  1405. }
  1406. var getIedByDesc = func(iedinfo map[string]orm.Params, iedtpye string, desc string) ([]string, []string) {
  1407. scdParseMgr := new(ScdParse)
  1408. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1409. r1 := []string{}
  1410. r2 := []string{}
  1411. for vn, row := range iedinfo {
  1412. if strings.HasPrefix(vn, iedtpye) {
  1413. v := tools.IsEmpty(row["ied_desc"])
  1414. if v == "" {
  1415. if scdXmlObj == nil {
  1416. continue
  1417. }
  1418. scdNode := new(ScdNode)
  1419. ied := scdNode.GetIed(scdXmlObj, "", vn)
  1420. if ied == nil {
  1421. continue
  1422. }
  1423. v = ied.Desc
  1424. }
  1425. if strings.Contains(v, desc) {
  1426. r1 = append(r1, v)
  1427. r2 = append(r2, vn)
  1428. }
  1429. }
  1430. }
  1431. return r1, r2
  1432. }
  1433. //判断是否将各电压等级的保护装置合并还是分开的间隔
  1434. //如果存在高中低压的保护装置,则说明是分开的主变间隔
  1435. ptCode := c.getIedTypeCode(modelid, "PT")
  1436. volValue := "" //电压等级值
  1437. if strings.Index(","+iedtypes+",", ","+ptCode+",") == -1 {
  1438. //判断主变保护是否是按电压等级分开配置的模型
  1439. h, m, l := c.getIedListByVol(ptCode, ieds, volMap)
  1440. if strings.Contains(iedtypes, ptCode+"#H") && len(h) > 0 {
  1441. //高压侧装置
  1442. volValue = "H"
  1443. } else if strings.Contains(iedtypes, ptCode+"#M") && len(m) > 0 {
  1444. volValue = "M"
  1445. } else if strings.Contains(iedtypes, ptCode+"#L") && len(l) > 0 {
  1446. volValue = "L"
  1447. }
  1448. }
  1449. pmCode := c.getIedTypeCode(modelid, "PM")
  1450. mmCode := c.getIedTypeCode(modelid, "MM")
  1451. ctCode := c.getIedTypeCode(modelid, "CT")
  1452. delPm := false
  1453. delMm := false
  1454. for _, row := range ieds {
  1455. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != ptCode[0:1] || tools.IsEmpty(row["p_type"]) != ptCode[1:] {
  1456. continue
  1457. }
  1458. if _, h := groupList[ptCode]; h {
  1459. //装置如果是分组成员装置,则不用检测
  1460. continue
  1461. }
  1462. pl_iedname := tools.IsEmpty(row["ied_name"])
  1463. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1464. areadesc := tools.IsEmpty(row["ied_desc"])
  1465. if areadesc == "" {
  1466. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1467. if iedobj != nil {
  1468. areadesc = iedobj.Desc
  1469. } else {
  1470. areadesc = tools.IsEmpty(row["area_name"])
  1471. }
  1472. }
  1473. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1474. //添加间隔数据
  1475. dbdata := T_data_check_area{
  1476. ModelId: modelid,
  1477. ScdId: c.ScdId,
  1478. AreaType: "T",
  1479. AreaName: areadesc + iednameParts[7],
  1480. }
  1481. newid, err := db.Insert(&dbdata)
  1482. if err != nil {
  1483. logger.Logger.Error(err)
  1484. return
  1485. }
  1486. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1487. insvalues := []string{}
  1488. inAreaIedName := ""
  1489. hasIedNameMap := map[string]int{}
  1490. //insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "T"))
  1491. for _, ty := range strings.Split(iedtypes, ",") {
  1492. inAreaIedName = ""
  1493. if _, h := groupList[ty]; h {
  1494. //装置如果是分组成员装置,则不用检测
  1495. continue
  1496. }
  1497. //判断是否指定的套别标识
  1498. abCode := c.getIedTypeABCode(ty)
  1499. if abCode != "" {
  1500. iednameParts[7] = abCode
  1501. }
  1502. tyCode := c.getIedTypeCode(modelid, ty)
  1503. if _, h := groupList[tyCode]; h {
  1504. //装置如果是分组成员装置,则不用检测
  1505. continue
  1506. }
  1507. if tyCode[0:len(pmCode)] == pmCode {
  1508. //PM和MM最后处理
  1509. delPm = true
  1510. continue
  1511. }
  1512. if tyCode[0:len(mmCode)] == mmCode {
  1513. //PM和MM最后处理
  1514. delMm = true
  1515. continue
  1516. }
  1517. ptype := strings.Split(tyCode, "#")[0]
  1518. //判断间隔是否需要包含差动装置
  1519. if strings.Contains(tyCode, "#C") {
  1520. _, iedname := getIedByDesc(ieds, ptype, "差动")
  1521. if len(iedname) > 0 {
  1522. for _, in := range iedname {
  1523. tmpIednameParts := scdParseMgr.ParseIedName(in)
  1524. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1525. if hasIedNameMap[in] == 1 {
  1526. break
  1527. }
  1528. hasIedNameMap[in] = 1
  1529. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
  1530. break
  1531. }
  1532. }
  1533. }
  1534. continue
  1535. }
  1536. //判断间隔是否需要包含本体保护装置
  1537. if strings.Contains(tyCode, "#0") {
  1538. _, iedname := getIedByDesc(ieds, ptype, "本体")
  1539. if len(iedname) > 0 {
  1540. for _, in := range iedname {
  1541. tmpIednameParts := scdParseMgr.ParseIedName(in)
  1542. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1543. if hasIedNameMap[in] == 1 {
  1544. break
  1545. }
  1546. hasIedNameMap[in] = 1
  1547. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, in, ptype[0:1], ptype[1:]))
  1548. break
  1549. }
  1550. }
  1551. }
  1552. continue
  1553. }
  1554. dlIeds := []orm.Params{}
  1555. imtcode := c.getIedTypeCode(modelid, tyCode)
  1556. h, m, l := c.getIedListByVol(imtcode, ieds, volMap, abCode)
  1557. //logger.Logger.Debug(fmt.Sprintf("tyCode:%s H:%+v,M:%+v,L:%+v", tyCode, h, m, l))
  1558. if volValue == "" || volValue == "H" || strings.Contains(tyCode, "#H") {
  1559. dlIeds = append(dlIeds, h...)
  1560. }
  1561. if volValue == "" || volValue == "M" || strings.Contains(tyCode, "#M") {
  1562. dlIeds = append(dlIeds, m...)
  1563. }
  1564. if volValue == "" || volValue == "L" || strings.Contains(tyCode, "#L") {
  1565. dlIeds = append(dlIeds, l...)
  1566. }
  1567. for _, r := range dlIeds {
  1568. inAreaIedName = tools.IsEmpty(r["ied_name"])
  1569. if hasIedNameMap[inAreaIedName] == 1 {
  1570. continue
  1571. }
  1572. hasIedNameMap[inAreaIedName] = 1
  1573. tmpIednameParts := scdParseMgr.ParseIedName(inAreaIedName)
  1574. if tyCode[0:len(ctCode)] == ctCode {
  1575. //CT单独处理。它可能不分AB套
  1576. lastChar := tmpIednameParts[7]
  1577. if tmpIednameParts[6] == iednameParts[6] && (lastChar == "" || lastChar == iednameParts[7]) {
  1578. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1579. }
  1580. } else {
  1581. if tmpIednameParts[6] == iednameParts[6] && tmpIednameParts[7] == iednameParts[7] {
  1582. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1583. }
  1584. }
  1585. }
  1586. }
  1587. //最后处理PM和MM
  1588. inAreaIedName = c.getPMName(iednameParts, ieds)
  1589. if delPm && inAreaIedName != "" {
  1590. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "P", "M"))
  1591. //pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1592. //使用PM装置的名称去定义MM的名称
  1593. inAreaIedName = c.getMMName(iednameParts, ieds, iednameParts[7])
  1594. if delMm && inAreaIedName != "" {
  1595. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M"))
  1596. }
  1597. }
  1598. //写数据库
  1599. if len(insvalues) > 0 {
  1600. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1601. }
  1602. if err != nil {
  1603. logger.Logger.Error(err)
  1604. return
  1605. }
  1606. }
  1607. }
  1608. //线路间隔分析
  1609. //vol:电压等级
  1610. func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1611. scdParseMgr := new(ScdParse)
  1612. scdNodeMgr := new(ScdNode)
  1613. db := orm.NewOrm()
  1614. //获取装置分组信息
  1615. bgm := new(SysCheckModelIedtypeGroupMgr)
  1616. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1617. groupList := bgm.List()
  1618. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1619. iedCode := c.getIedTypeCode(modelid, "PL")
  1620. for _, row := range ieds {
  1621. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != iedCode[0:1] || tools.IsEmpty(row["p_type"]) != iedCode[1:] {
  1622. continue
  1623. }
  1624. mmIedName := ""
  1625. pl_iedname := tools.IsEmpty(row["ied_name"])
  1626. if _, h := groupList[pl_iedname]; h {
  1627. //装置如果是分组成员装置,则不用检测
  1628. continue
  1629. }
  1630. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1631. areadesc := tools.IsEmpty(row["ied_desc"])
  1632. if areadesc == "" {
  1633. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1634. if iedobj != nil {
  1635. areadesc = iedobj.Desc
  1636. } else {
  1637. areadesc = tools.IsEmpty(row["area_name"])
  1638. }
  1639. }
  1640. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1641. //添加间隔数据
  1642. dbdata := T_data_check_area{
  1643. ModelId: modelid,
  1644. ScdId: c.ScdId,
  1645. AreaType: "L",
  1646. AreaName: areadesc + iednameParts[7],
  1647. }
  1648. newid, err := db.Insert(&dbdata)
  1649. if err != nil {
  1650. logger.Logger.Error(err)
  1651. return
  1652. }
  1653. hasIedNameMap := map[string]int{}
  1654. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1655. insvalues := []string{}
  1656. pmCode := c.getIedTypeCode(modelid, "PM")
  1657. mmCode := c.getIedTypeCode(modelid, "MM")
  1658. clCode := c.getIedTypeCode(modelid, "CL")
  1659. for _, ty := range strings.Split(iedtypes, ",") {
  1660. inAreaIedName := ""
  1661. if _, h := groupList[ty]; h {
  1662. //装置如果是分组成员装置,则不用检测
  1663. continue
  1664. }
  1665. abCode := c.getIedTypeABCode(ty)
  1666. if abCode != "" {
  1667. iednameParts[7] = abCode
  1668. }
  1669. tyCode := c.getIedTypeCode(modelid, ty)
  1670. if _, h := groupList[tyCode]; h {
  1671. //装置如果是分组成员装置,则不用检测
  1672. continue
  1673. }
  1674. ptype := strings.Split(tyCode, "#")[0]
  1675. if ptype == pmCode {
  1676. //母线保护和母线合并单元装置编号跟随变压器
  1677. //查找变压器编号
  1678. //1号变压器->2号变压器->3号
  1679. inAreaIedName = c.getPMName(iednameParts, ieds)
  1680. if hasIedNameMap[inAreaIedName] == 1 {
  1681. continue
  1682. }
  1683. hasIedNameMap[inAreaIedName] = 1
  1684. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:2]))
  1685. continue
  1686. } else if ptype == mmCode {
  1687. //最后处理
  1688. continue
  1689. } else {
  1690. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1691. }
  1692. if strings.Index("ABCDE", iednameParts[7]) > -1 {
  1693. //最后一位是字母则说明是AB套
  1694. switch ptype {
  1695. case clCode:
  1696. if strings.Contains(iedtypes, "PLC") || strings.Contains(iedtypes, "PCL") {
  1697. //不处理CL装置
  1698. } else {
  1699. //测控装置,先判断是否分了AB套,没有标识(ied名称的最后一位是否是字母)则说明是多套共用装置
  1700. if ieds[inAreaIedName] == nil {
  1701. //当前测控装置没有分AB套
  1702. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1703. }
  1704. }
  1705. break
  1706. default:
  1707. break
  1708. }
  1709. }
  1710. if hasIedNameMap[inAreaIedName] == 1 {
  1711. continue
  1712. }
  1713. hasIedNameMap[inAreaIedName] = 1
  1714. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1715. }
  1716. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1717. if err != nil {
  1718. logger.Logger.Error(err)
  1719. return
  1720. }
  1721. //如果mm装置还未确定
  1722. if mmIedName == "" {
  1723. //pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1724. inAreaIedName := c.getMMName(iednameParts, ieds, iednameParts[7])
  1725. _, err = db.Raw(ins1 + fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, "M", "M")).Exec()
  1726. if err != nil {
  1727. logger.Logger.Error(err)
  1728. return
  1729. }
  1730. }
  1731. }
  1732. }
  1733. //母联间隔分析
  1734. func (c *CheckAreaMgr) pJ(modelid int, vol, iedtypes string, ieds map[string]orm.Params, pjIed string) {
  1735. scdParseMgr := new(ScdParse)
  1736. scdNodeMgr := new(ScdNode)
  1737. db := orm.NewOrm()
  1738. pjIed = c.getIedTypeCode(modelid, pjIed)
  1739. scdXmlObject, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1740. for _, row := range ieds {
  1741. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != pjIed[0:1] || tools.IsEmpty(row["p_type"]) != pjIed[1:2] {
  1742. continue
  1743. }
  1744. pmIedName := ""
  1745. mmIedName := ""
  1746. pl_iedname := tools.IsEmpty(row["ied_name"])
  1747. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1748. areadesc := tools.IsEmpty(row["ied_desc"])
  1749. if areadesc == "" {
  1750. iedobj := scdNodeMgr.GetIed(scdXmlObject, "", pl_iedname)
  1751. if iedobj != nil {
  1752. areadesc = iedobj.Desc
  1753. } else {
  1754. areadesc = tools.IsEmpty(row["area_name"])
  1755. }
  1756. }
  1757. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1758. //添加间隔数据
  1759. dbdata := T_data_check_area{
  1760. ModelId: modelid,
  1761. ScdId: c.ScdId,
  1762. AreaType: "J",
  1763. AreaName: areadesc + iednameParts[7],
  1764. }
  1765. newid, err := db.Insert(&dbdata)
  1766. if err != nil {
  1767. logger.Logger.Error(err)
  1768. return
  1769. }
  1770. hasIedNameMap := map[string]int{}
  1771. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1772. insvalues := []string{}
  1773. pmCode := c.getIedTypeCode(modelid, "PM")
  1774. mmCode := c.getIedTypeCode(modelid, "MM")
  1775. for _, ty := range strings.Split(iedtypes, ",") {
  1776. abCode := c.getIedTypeABCode(ty)
  1777. if abCode != "" {
  1778. iednameParts[7] = abCode
  1779. }
  1780. tyCode := c.getIedTypeCode(modelid, ty)
  1781. ptype := strings.Split(tyCode, "#")[0]
  1782. inAreaIedName := ""
  1783. if ptype == pmCode {
  1784. //母线保护和母线合并单元装置编号跟随变压器
  1785. //查找变压器编号
  1786. //1号变压器->2号变压器->3号
  1787. inAreaIedName = c.getPMName(iednameParts, ieds)
  1788. pmIedName = inAreaIedName
  1789. if mmIedName == "" {
  1790. if hasIedNameMap[inAreaIedName] == 1 {
  1791. continue
  1792. }
  1793. hasIedNameMap[inAreaIedName] = 1
  1794. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1795. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1796. //使用PM装置的名称去定义MM的名称
  1797. tyCode = "MM"
  1798. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1799. mmIedName = inAreaIedName
  1800. }
  1801. } else if ptype == mmCode {
  1802. if pmIedName != "" && mmIedName == "" {
  1803. pmIedNameParts := scdParseMgr.ParseIedName(pmIedName)
  1804. //使用PM装置的名称去定义MM的名称
  1805. inAreaIedName = c.getMMName(pmIedNameParts, ieds, iednameParts[7])
  1806. mmIedName = inAreaIedName
  1807. } else {
  1808. continue
  1809. }
  1810. } else {
  1811. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + iednameParts[7]
  1812. //判断与基准保护装置相同套号的装置是否存在
  1813. if ieds[inAreaIedName] == nil {
  1814. //尝试去除套号
  1815. inAreaIedName = ptype + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6]
  1816. }
  1817. }
  1818. if hasIedNameMap[inAreaIedName] == 1 {
  1819. continue
  1820. }
  1821. hasIedNameMap[inAreaIedName] = 1
  1822. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1823. }
  1824. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1825. if err != nil {
  1826. logger.Logger.Error(err)
  1827. return
  1828. }
  1829. }
  1830. }
  1831. //母线间隔装置提取
  1832. func (c *CheckAreaMgr) pM(modelid int, vol, iedtypes string, ieds map[string]orm.Params) {
  1833. scdParseMgr := new(ScdParse)
  1834. scdNodeMgr := new(ScdNode)
  1835. db := orm.NewOrm()
  1836. //获取当前站的各电压等级
  1837. volRows := []orm.Params{}
  1838. _, 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)
  1839. if err != nil {
  1840. logger.Logger.Error(err)
  1841. return
  1842. }
  1843. if len(volRows) == 0 {
  1844. logger.Logger.Error(errors.New("该scd未发现任何电压等级的装置"))
  1845. return
  1846. }
  1847. volMap := map[string]string{}
  1848. volMap["hight"] = tools.IsEmpty(volRows[0]["vol"]) //高压电压
  1849. if len(volRows) == 2 {
  1850. volMap["middle"] = ""
  1851. volMap["low"] = volRows[1]["vol"].(string) //低压电压等级
  1852. } else {
  1853. volMap["middle"] = volRows[1]["vol"].(string) //中压电压等级
  1854. volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
  1855. }
  1856. //获取装置分组信息
  1857. bgm := new(SysCheckModelIedtypeGroupMgr)
  1858. bgm.Model = T_data_model_iedtype_group{ModelId: modelid}
  1859. groupList := bgm.List()
  1860. scdXmlObj, _ := scdParseMgr.GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdId))
  1861. iedCode := c.getIedTypeCode(modelid, "PM")
  1862. for _, row := range ieds {
  1863. if tools.IsEmpty(row["vol"]) != vol || tools.IsEmpty(row["ied_type"]) != iedCode[0:1] || tools.IsEmpty(row["p_type"]) != iedCode[1:] {
  1864. continue
  1865. }
  1866. pl_iedname := tools.IsEmpty(row["ied_name"])
  1867. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  1868. areadesc := tools.IsEmpty(row["ied_desc"])
  1869. if areadesc == "" {
  1870. iedobj := scdNodeMgr.GetIed(scdXmlObj, "", pl_iedname)
  1871. if iedobj != nil {
  1872. areadesc = iedobj.Desc
  1873. } else {
  1874. areadesc = tools.IsEmpty(row["area_name"])
  1875. }
  1876. }
  1877. areadesc = strings.ReplaceAll(areadesc, "装置", "")
  1878. //添加间隔数据
  1879. dbdata := T_data_check_area{
  1880. ModelId: modelid,
  1881. ScdId: c.ScdId,
  1882. AreaType: "M",
  1883. AreaName: areadesc,
  1884. }
  1885. newid, err := db.Insert(&dbdata)
  1886. if err != nil {
  1887. logger.Logger.Error(err)
  1888. return
  1889. }
  1890. pmVol := "" //当前PM装置的电压等级
  1891. for volLevel, volValue := range volMap {
  1892. if volValue == iednameParts[3]+iednameParts[4] {
  1893. pmVol = volLevel
  1894. break
  1895. }
  1896. }
  1897. hasIedNameMap := map[string]int{}
  1898. ins1 := "insert into t_data_check_area_ied(scd_id,area_id,ied_name,ied_type,p_type)values"
  1899. insvalues := []string{}
  1900. mmCode := c.getIedTypeCode(modelid, "MM")
  1901. for _, ty := range strings.Split(iedtypes, ",") {
  1902. inAreaIedName := ""
  1903. if _, h := groupList[ty]; h {
  1904. //装置如果是分组成员装置,则不用检测
  1905. continue
  1906. }
  1907. abCode := c.getIedTypeABCode(ty)
  1908. if abCode == "" {
  1909. //未特别指定套别时,采用主IED装置的套别
  1910. abCode = iednameParts[7]
  1911. }
  1912. tyCode := c.getIedTypeCode(modelid, ty)
  1913. if _, h := groupList[tyCode]; h {
  1914. //装置如果是分组成员装置,则不用检测
  1915. continue
  1916. }
  1917. ptype := strings.Split(tyCode, "#")[0]
  1918. if tyCode == mmCode {
  1919. //MM:母线合并单元
  1920. inAreaIedName = c.getMMName(iednameParts, ieds, abCode)
  1921. if inAreaIedName != "" {
  1922. if hasIedNameMap[inAreaIedName] == 1 {
  1923. continue
  1924. }
  1925. hasIedNameMap[inAreaIedName] = 1
  1926. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1927. }
  1928. } else {
  1929. //需要查找同电压等级的所有同类同套装置
  1930. h, m, l := c.getIedListByVol(tyCode, ieds, volMap, abCode)
  1931. //logger.Logger.Debug(fmt.Sprintf("当前PM装置:%s 电压等级:%s 提取类型:%s 套别:%s h:%+v,m:%+v,l:%+v", pl_iedname, pmVol, ptype, abCode, h, m, l))
  1932. switch pmVol {
  1933. case "hight":
  1934. for _, item := range h {
  1935. inAreaIedName = tools.IsEmpty(item["ied_name"])
  1936. if hasIedNameMap[inAreaIedName] == 1 {
  1937. continue
  1938. }
  1939. hasIedNameMap[inAreaIedName] = 1
  1940. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1941. }
  1942. break
  1943. case "middle":
  1944. for _, item := range m {
  1945. inAreaIedName = tools.IsEmpty(item["ied_name"])
  1946. if hasIedNameMap[inAreaIedName] == 1 {
  1947. continue
  1948. }
  1949. hasIedNameMap[inAreaIedName] = 1
  1950. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1951. }
  1952. break
  1953. case "low":
  1954. for _, item := range l {
  1955. inAreaIedName = tools.IsEmpty(item["ied_name"])
  1956. if hasIedNameMap[inAreaIedName] == 1 {
  1957. continue
  1958. }
  1959. hasIedNameMap[inAreaIedName] = 1
  1960. insvalues = append(insvalues, fmt.Sprintf("(%d,%d,'%s','%s','%s')", c.ScdId, newid, inAreaIedName, ptype[0:1], ptype[1:]))
  1961. }
  1962. break
  1963. }
  1964. }
  1965. }
  1966. if len(insvalues) == 0 {
  1967. continue
  1968. }
  1969. _, err = db.Raw(ins1 + strings.Join(insvalues, ",")).Exec()
  1970. if err != nil {
  1971. logger.Logger.Error(err)
  1972. return
  1973. }
  1974. }
  1975. }
  1976. //母联间隔装置关系检查
  1977. 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) {
  1978. modelidInt, _ := strconv.Atoi(modelid)
  1979. pjIed = c.getIedTypeCode(modelidInt, pjIed)
  1980. masterIed := new(node_attr.NIED)
  1981. findIedName := ""
  1982. for _, row2 := range area_ieds {
  1983. findIedName = tools.IsEmpty(row2["ied_name"])
  1984. if strings.HasPrefix(findIedName, pjIed) {
  1985. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  1986. break
  1987. }
  1988. }
  1989. if masterIed == nil {
  1990. return
  1991. }
  1992. dealFromIed := map[string]int{}
  1993. for _, row := range ied_refs {
  1994. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  1995. toiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"]))
  1996. reftype := tools.IsEmpty(row["in_type"])
  1997. tmpFromAreaIeds := []orm.Params{}
  1998. tmpToAreaIeds := []orm.Params{}
  1999. for _, row2 := range area_ieds {
  2000. findIedName = tools.IsEmpty(row2["ied_name"])
  2001. if strings.HasPrefix(findIedName, fromiedtype) {
  2002. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2003. if masterIed != nil {
  2004. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2005. } else {
  2006. if dealFromIed[findIedName] == 0 {
  2007. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2008. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2009. //检查未通过
  2010. scdNodeRule.AppendFcdaCheckResult(r)
  2011. }
  2012. dealFromIed[findIedName] = 1
  2013. }
  2014. }
  2015. if strings.HasPrefix(findIedName, toiedtype) {
  2016. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2017. }
  2018. }
  2019. if len(tmpFromAreaIeds) == 0 {
  2020. continue
  2021. }
  2022. if len(tmpToAreaIeds) == 0 {
  2023. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  2024. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2025. //检查未通过
  2026. scdNodeRule.AppendFcdaCheckResult(r)
  2027. continue
  2028. }
  2029. toIedname := ""
  2030. for _, row2 := range tmpFromAreaIeds {
  2031. findIedName = tools.IsEmpty(row2["ied_name"])
  2032. hasToIedRef := false
  2033. hasToIed := false
  2034. for _, row3 := range tmpToAreaIeds {
  2035. toIedname = tools.IsEmpty(row3["ied_name"])
  2036. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  2037. if masterIed != nil {
  2038. hasToIed = true
  2039. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2040. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2041. logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2042. if inout != nil {
  2043. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2044. for _, ieditem := range outiedlist {
  2045. outiedname := ieditem["ref_ied_name"].(string)
  2046. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2047. hasToIedRef = true
  2048. break
  2049. }
  2050. }
  2051. }
  2052. if !hasToIedRef {
  2053. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2054. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2055. //检查未通过
  2056. scdNodeRule.AppendFcdaCheckResult(r)
  2057. }
  2058. }
  2059. }
  2060. if !hasToIed {
  2061. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2062. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2063. //检查未通过
  2064. scdNodeRule.AppendFcdaCheckResult(r)
  2065. }
  2066. }
  2067. }
  2068. }
  2069. //线路间隔装置关系检查
  2070. 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) {
  2071. modelidInt, _ := strconv.Atoi(modelid)
  2072. //获取装置分组信息
  2073. bgm := new(SysCheckModelIedtypeGroupMgr)
  2074. bgm.Model = T_data_model_iedtype_group{ModelId: modelidInt}
  2075. groupList := bgm.List()
  2076. plIed := c.getIedTypeCode(modelidInt, "PL")
  2077. if v, h := groupList[plIed]; h {
  2078. //装置如果是分组成员装置
  2079. plIed = v
  2080. }
  2081. masterIed := new(node_attr.NIED)
  2082. findIedName := ""
  2083. for _, row2 := range area_ieds {
  2084. findIedName = tools.IsEmpty(row2["ied_name"])
  2085. if strings.HasPrefix(findIedName, plIed) {
  2086. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2087. break
  2088. }
  2089. }
  2090. if masterIed == nil {
  2091. return
  2092. }
  2093. logger.Logger.Debug(fmt.Sprintf("开始分析模型%d的线路间隔关系", modelidInt))
  2094. dealFromIed := map[string]int{}
  2095. for _, row := range ied_refs {
  2096. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  2097. toiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"]))
  2098. reftype := tools.IsEmpty(row["in_type"])
  2099. tmpFromAreaIeds := []orm.Params{}
  2100. tmpToAreaIeds := []orm.Params{}
  2101. for _, row2 := range area_ieds {
  2102. findIedName = tools.IsEmpty(row2["ied_name"])
  2103. if strings.HasPrefix(findIedName, fromiedtype) {
  2104. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2105. if masterIed != nil {
  2106. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2107. } else {
  2108. if dealFromIed[findIedName] == 0 {
  2109. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2110. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2111. "ied_name": findIedName,
  2112. "ied_desc": "",
  2113. "out_ied_name": "",
  2114. "out_ied_desc": "",
  2115. "fcda_desc": "",
  2116. "fcda_addr": "",
  2117. "out_fcda_desc": "",
  2118. "out_fcda_addr": "",
  2119. "error_type": "9",
  2120. }
  2121. //检查未通过
  2122. scdNodeRule.AppendFcdaCheckResult(r)
  2123. }
  2124. dealFromIed[findIedName] = 1
  2125. }
  2126. }
  2127. if strings.HasPrefix(findIedName, toiedtype) {
  2128. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2129. }
  2130. }
  2131. if len(tmpFromAreaIeds) == 0 {
  2132. continue
  2133. }
  2134. if len(tmpToAreaIeds) == 0 {
  2135. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
  2136. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
  2137. //检查未通过
  2138. scdNodeRule.AppendFcdaCheckResult(r)
  2139. continue
  2140. }
  2141. toIedname := ""
  2142. for _, row2 := range tmpFromAreaIeds {
  2143. findIedName = tools.IsEmpty(row2["ied_name"])
  2144. hasToIedRef := false
  2145. hasToIed := false
  2146. for _, row3 := range tmpToAreaIeds {
  2147. toIedname = tools.IsEmpty(row3["ied_name"])
  2148. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", toIedname)
  2149. if masterIed != nil {
  2150. hasToIed = true
  2151. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2152. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2153. //logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2154. if inout != nil {
  2155. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2156. for _, ieditem := range outiedlist {
  2157. outiedname := ieditem["ref_ied_name"].(string)
  2158. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2159. hasToIedRef = true
  2160. break
  2161. }
  2162. }
  2163. }
  2164. if !hasToIedRef {
  2165. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2166. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2167. "ied_name": findIedName,
  2168. "ied_desc": "",
  2169. "out_ied_name": toIedname,
  2170. "out_ied_desc": "",
  2171. "fcda_desc": "",
  2172. "fcda_addr": "",
  2173. "out_fcda_desc": "",
  2174. "out_fcda_addr": "",
  2175. "error_type": "9",
  2176. }
  2177. //检查未通过
  2178. scdNodeRule.AppendFcdaCheckResult(r)
  2179. }
  2180. }
  2181. }
  2182. if !hasToIed {
  2183. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2184. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2185. "ied_name": findIedName,
  2186. "ied_desc": "",
  2187. "out_ied_name": toIedname,
  2188. "out_ied_desc": "",
  2189. "fcda_desc": "",
  2190. "fcda_addr": "",
  2191. "out_fcda_desc": "",
  2192. "out_fcda_addr": "",
  2193. "error_type": "9",
  2194. }
  2195. //检查未通过
  2196. scdNodeRule.AppendFcdaCheckResult(r)
  2197. }
  2198. }
  2199. }
  2200. }
  2201. //变压器间隔装置关系检查
  2202. 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) {
  2203. masterIed := new(node_attr.NIED)
  2204. findIedName := ""
  2205. modelidInt, _ := strconv.Atoi(modelid)
  2206. ptIed := c.getIedTypeCode(modelidInt, "PT")
  2207. for _, row2 := range area_ieds {
  2208. findIedName = tools.IsEmpty(row2["ied_name"])
  2209. if strings.HasPrefix(findIedName, ptIed) {
  2210. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2211. break
  2212. }
  2213. }
  2214. if masterIed == nil {
  2215. return
  2216. }
  2217. scdParseMgr := new(ScdParse)
  2218. dealFromIed := map[string]int{}
  2219. for _, row := range ied_refs {
  2220. fromiedtype := c.getIedTypeCode(modelidInt, tools.IsEmpty(row["from_ied_code"]))
  2221. fromiedtype = strings.Split(fromiedtype, "#")[0] //去除后面的电压级别标识
  2222. toiedtype := strings.Split(c.getIedTypeCode(modelidInt, tools.IsEmpty(row["to_ied_code"])), "#")[0] //去除后面的电压级别标识
  2223. reftype := tools.IsEmpty(row["in_type"])
  2224. tmpFromAreaIeds := []orm.Params{}
  2225. tmpToAreaIeds := []orm.Params{}
  2226. for _, row2 := range area_ieds {
  2227. findIedName = tools.IsEmpty(row2["ied_name"])
  2228. if strings.HasPrefix(findIedName, fromiedtype) {
  2229. masterIed = scdNodeMgr.GetIed(scdXmlObj, "", findIedName)
  2230. if masterIed != nil {
  2231. tmpFromAreaIeds = append(tmpFromAreaIeds, row2)
  2232. } else {
  2233. if dealFromIed[findIedName] == 0 {
  2234. parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
  2235. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2236. "ied_name": findIedName,
  2237. "ied_desc": "",
  2238. "out_ied_name": "",
  2239. "out_ied_desc": "",
  2240. "fcda_desc": "",
  2241. "fcda_addr": "",
  2242. "out_fcda_desc": "",
  2243. "out_fcda_addr": "",
  2244. "error_type": "9",
  2245. }
  2246. //检查未通过
  2247. scdNodeRule.AppendFcdaCheckResult(r)
  2248. }
  2249. dealFromIed[findIedName] = 1
  2250. }
  2251. }
  2252. if strings.HasPrefix(findIedName, toiedtype) {
  2253. tmpToAreaIeds = append(tmpToAreaIeds, row2)
  2254. }
  2255. }
  2256. if len(tmpFromAreaIeds) == 0 {
  2257. continue
  2258. }
  2259. if len(tmpToAreaIeds) == 0 {
  2260. logger.Logger.Debug(fmt.Sprintf("缺失类型关联装置 :%+v", row))
  2261. parse_result := fmt.Sprintf("间隔%s缺失类型为%s的%s信号装置", area_name, toiedtype, reftype)
  2262. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2263. "ied_name": findIedName,
  2264. "ied_desc": "",
  2265. "out_ied_name": "",
  2266. "out_ied_desc": "",
  2267. "fcda_desc": "",
  2268. "fcda_addr": "",
  2269. "out_fcda_desc": "",
  2270. "out_fcda_addr": "",
  2271. "error_type": "9",
  2272. }
  2273. //检查未通过
  2274. scdNodeRule.AppendFcdaCheckResult(r)
  2275. continue
  2276. }
  2277. toIedname := ""
  2278. for _, row2 := range tmpFromAreaIeds {
  2279. findIedName = tools.IsEmpty(row2["ied_name"])
  2280. hasToIedRef := false
  2281. hasToIed := false
  2282. t1 := fromiedtype + "->" + toiedtype
  2283. volLevel := "" //电压等级
  2284. 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" {
  2285. ps := scdParseMgr.ParseIedName(findIedName)
  2286. volLevel = ps[3] + ps[4]
  2287. }
  2288. hasSameVolIed := false
  2289. for _, row3 := range tmpToAreaIeds {
  2290. toIedname = tools.IsEmpty(row3["ied_name"])
  2291. if volLevel != "" {
  2292. ps := scdParseMgr.ParseIedName(toIedname)
  2293. if volLevel != ps[3]+ps[4] {
  2294. //排除不是同一电压等级的装置
  2295. continue
  2296. }
  2297. hasSameVolIed = true
  2298. }
  2299. if scdNodeMgr.GetIed(scdXmlObj, "", toIedname) != nil {
  2300. hasToIed = true
  2301. // 获取该ied的输出(ref_type为0)装置,并从中检测是否存在toiedtype类型的装置
  2302. inout, _ := scdNodeMgr.GetIedRelations(map[string]interface{}{"scd_id": c.ScdId, "ied_name": findIedName})
  2303. //logger.Logger.Debug(fmt.Sprintf("ied:%s refs:%+v", findIedName, inout))
  2304. if inout != nil {
  2305. outiedlist := inout[findIedName].(orm.Params)["list"].([]orm.Params)
  2306. for _, ieditem := range outiedlist {
  2307. outiedname := ieditem["ref_ied_name"].(string)
  2308. if outiedname == toIedname && ieditem["ref_type"].(string) == "0" {
  2309. hasToIedRef = true
  2310. break
  2311. }
  2312. }
  2313. }
  2314. if !hasToIedRef {
  2315. parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
  2316. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2317. "ied_name": findIedName,
  2318. "ied_desc": "",
  2319. "out_ied_name": toIedname,
  2320. "out_ied_desc": "",
  2321. "fcda_desc": "",
  2322. "fcda_addr": "",
  2323. "out_fcda_desc": "",
  2324. "out_fcda_addr": "",
  2325. "error_type": "9",
  2326. }
  2327. //检查未通过
  2328. scdNodeRule.AppendFcdaCheckResult(r)
  2329. }
  2330. }
  2331. if hasSameVolIed {
  2332. break
  2333. }
  2334. }
  2335. if toiedtype != ptIed {
  2336. if volLevel != "" && !hasSameVolIed {
  2337. parse_result := fmt.Sprintf("间隔%s的装置%s缺失同电压等级的关联类型%s装置", area_name, findIedName, toiedtype)
  2338. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2339. "ied_name": findIedName,
  2340. "ied_desc": "",
  2341. "out_ied_name": "",
  2342. "out_ied_desc": "",
  2343. "fcda_desc": "",
  2344. "fcda_addr": "",
  2345. "out_fcda_desc": "",
  2346. "out_fcda_addr": "",
  2347. "error_type": "9",
  2348. }
  2349. //检查未通过
  2350. scdNodeRule.AppendFcdaCheckResult(r)
  2351. } else if !hasToIed {
  2352. parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
  2353. r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
  2354. "ied_name": findIedName,
  2355. "ied_desc": "",
  2356. "out_ied_name": toIedname,
  2357. "out_ied_desc": "",
  2358. "fcda_desc": "",
  2359. "fcda_addr": "",
  2360. "out_fcda_desc": "",
  2361. "out_fcda_addr": "",
  2362. "error_type": "9",
  2363. }
  2364. //检查未通过
  2365. scdNodeRule.AppendFcdaCheckResult(r)
  2366. }
  2367. }
  2368. }
  2369. }
  2370. }
  2371. //根据参考ied name找出应该关联PM装置
  2372. //abcode:套别标识代码。可选。不指定时将自动从iedtype识别
  2373. func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params, abcode ...string) string {
  2374. //如果只有一个PM装置,则直接返回该 装置
  2375. pmLst := []string{}
  2376. for n, _ := range ieds {
  2377. if strings.HasPrefix(n, "PM"+iednameParts[3]+iednameParts[4]) {
  2378. pmLst = append(pmLst, n)
  2379. }
  2380. }
  2381. if len(pmLst) == 1 {
  2382. return pmLst[0]
  2383. }
  2384. ab := ""
  2385. if len(abcode) > 0 {
  2386. ab = abcode[0]
  2387. }
  2388. //暴力匹配
  2389. for _, n := range pmLst {
  2390. if ab != "" {
  2391. //优先完全匹配指定套别
  2392. if strings.HasSuffix(n, ab) {
  2393. return n
  2394. }
  2395. continue
  2396. }
  2397. if strings.HasSuffix(n, iednameParts[7]) {
  2398. return n
  2399. }
  2400. }
  2401. return ""
  2402. }
  2403. //根据参考ied name找出应该关联MM装置
  2404. func (c *CheckAreaMgr) getMMName(iednameParts []string, ieds map[string]orm.Params, ab string) string {
  2405. mmLst := []string{}
  2406. for n, _ := range ieds {
  2407. if strings.HasPrefix(n, "MM"+iednameParts[3]+iednameParts[4]) {
  2408. mmLst = append(mmLst, n)
  2409. }
  2410. }
  2411. if len(mmLst) == 1 {
  2412. return mmLst[0]
  2413. }
  2414. for _, n := range mmLst {
  2415. if ab != "" && strings.HasSuffix(n, ab) {
  2416. return n
  2417. }
  2418. if ab == "" && strings.HasSuffix(n, iednameParts[5]+iednameParts[6]) {
  2419. return n
  2420. }
  2421. }
  2422. //理论上的装置名称
  2423. return "MM" + iednameParts[3] + iednameParts[4] + iednameParts[5] + iednameParts[6] + ab
  2424. }
  2425. //获取装置编码中的套别代码(A、B..)
  2426. func (c *CheckAreaMgr) getIedTypeABCode(iedtype string) string {
  2427. if strings.Index(iedtype, "-") > 0 {
  2428. return strings.Split(iedtype, "-")[1]
  2429. }
  2430. return ""
  2431. }
  2432. //根据当前设备列表,分析出电压等级(高、中、低)的设备列表
  2433. // CT测控、IT智能终端、MT合并单元需要判断是否是本体装置,是则将其归为主变高压侧
  2434. //iedtype:装置编码
  2435. //ieds:装置筛选范围列表
  2436. //vollevel:电压等级代码。H:高压 M:中压 L:低压
  2437. //abcode:套别标识代码。可选。不指定时将自动从iedtype识别
  2438. func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string, abcode ...string) (hightLst, middleLst, lowLst []orm.Params) {
  2439. tmpLst := map[string][]orm.Params{}
  2440. for _, v := range vollevel {
  2441. tmpLst[v] = []orm.Params{}
  2442. }
  2443. ab := ""
  2444. if len(abcode) > 0 {
  2445. ab = abcode[0]
  2446. }
  2447. if strings.Index(iedtype, "-") > 0 {
  2448. //去除套别标识
  2449. iedtype = strings.Split(iedtype, "-")[0]
  2450. if ab == "" {
  2451. ab = strings.Split(iedtype, "-")[1]
  2452. }
  2453. }
  2454. it := strings.Split(iedtype, "#")
  2455. scdParseMgr := new(ScdParse)
  2456. for _, row := range ieds {
  2457. pl_iedname := tools.IsEmpty(row["ied_name"])
  2458. if pl_iedname[0:len(it[0])] != it[0] {
  2459. continue
  2460. }
  2461. iednameParts := scdParseMgr.ParseIedName(pl_iedname)
  2462. if ab != "" && iednameParts[7] != ab {
  2463. //指定了套别时,装置套别必须与指定套别完全相同
  2464. continue
  2465. }
  2466. volvalue := iednameParts[3] + iednameParts[4]
  2467. if tmpLst[volvalue] == nil {
  2468. tmpLst[volvalue] = []orm.Params{row}
  2469. } else {
  2470. tmpLst[volvalue] = append(tmpLst[volvalue], row)
  2471. }
  2472. }
  2473. if len(it) > 1 {
  2474. if it[1] == "H" {
  2475. return tmpLst[vollevel["hight"]], []orm.Params{}, []orm.Params{}
  2476. }
  2477. if it[1] == "M" {
  2478. return []orm.Params{}, tmpLst[vollevel["middle"]], []orm.Params{}
  2479. }
  2480. if it[1] == "L" {
  2481. return []orm.Params{}, []orm.Params{}, tmpLst[vollevel["low"]]
  2482. }
  2483. }
  2484. return tmpLst[vollevel["hight"]], tmpLst[vollevel["middle"]], tmpLst[vollevel["low"]]
  2485. }
  2486. func (c *CheckAreaMgr) GetCheckResult(scdid int64) ([]orm.Params, error) {
  2487. db := orm.NewOrm()
  2488. rowset := []orm.Params{}
  2489. 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"
  2490. _, err := db.Raw(sql, scdid).Values(&rowset)
  2491. return rowset, err
  2492. }