checktools_area.go 104 KB

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