scd_diff_compare.go 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930
  1. package bo
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "runtime"
  8. "scd_check_tools/logger"
  9. "scd_check_tools/models/enum"
  10. "scd_check_tools/models/node_attr"
  11. "scd_check_tools/mqtt"
  12. "scd_check_tools/tools"
  13. "strconv"
  14. "strings"
  15. "sync"
  16. "time"
  17. "github.com/astaxie/beego/orm"
  18. )
  19. type t_scd_diff_compare struct {
  20. Id int64 `orm:"pk;auto"`
  21. Name string
  22. //对比的文件类型。值为scd|icd等
  23. FileType string
  24. SourceId int64
  25. TargetId int64
  26. StationId int
  27. NodeState int
  28. AttrState int
  29. SourceFile string
  30. TargetFile string
  31. }
  32. type t_scd_diff_compare_detail struct {
  33. Id int64 `orm:"pk;auto"`
  34. IedName string `json:"ied_name"`
  35. IedDesc string `json:"ied_desc"`
  36. CompareId int64 `json:"compare_id"`
  37. //发生差异的对象类型:node\attr
  38. DiffObjectType string `json:"diff_object_type"`
  39. DiffObjectNodeId int64 `json:"diff_object_node_id"`
  40. DiffObjectName string `json:"diff_object_name"`
  41. DiffSourceNodeId int64 `json:"diff_source_node_id"`
  42. SourceLineNo int64 `json:"source_line_no"`
  43. ObjectLineNo int64 `json:"object_line_no"`
  44. //发生差异的操作:新增i\修改u\删除d
  45. DiffOpt string `json:"diff_opt"`
  46. //差异描述
  47. DiffDesc string `json:"diff_desc"`
  48. }
  49. //文件scd文件差异对比
  50. type ScdCompare struct {
  51. Userinfo map[string]interface{}
  52. lock sync.RWMutex
  53. StationId int
  54. //如果是2个对比文件时,需要对比的文件ID列表。仅当CompareType为ccd\cid\ccd_cid_scd\icd_scd时有效
  55. CompFileIds []string
  56. //对比的文件类型码:scd|icd|ccd|...。全大写
  57. CompareType string
  58. //用于对比的scd文件ID
  59. Sourceid int64
  60. //被比较的scd文件id
  61. Targetid int64
  62. //当前对比记录ID
  63. CurrCompareRecord t_scd_diff_compare
  64. //对比结果队列
  65. CompareResultList []t_scd_diff_compare_detail
  66. //对比文件的基本信息
  67. CompareBaseInfo map[string]interface{}
  68. }
  69. func init() {
  70. orm.RegisterModel(new(t_scd_diff_compare))
  71. orm.RegisterModel(new(t_scd_diff_compare_detail))
  72. }
  73. func (c *ScdCompare) GetCheckToolsTreeRoot(scdid, id, pid int64, datatype string) ([]orm.Params, error) {
  74. db := orm.NewOrm()
  75. reuslt := []orm.Params{}
  76. areaMgr := new(ScdAreaMgr)
  77. if id == 0 {
  78. //获取间隔列表
  79. areaList, err := areaMgr.GetAreaList(scdid)
  80. if err != nil {
  81. return nil, err
  82. }
  83. //获取该电压等级下的间隔列表
  84. for _, ararow := range areaList {
  85. //if tools.IsEmpty(ararow["voltage_level"]) == tools.IsEmpty(row2["id"]) {
  86. ararow["title"] = ararow["name"]
  87. ararow["datatype"] = "area"
  88. ararow["isParent"] = "true"
  89. ararow["pid"] = tools.IsEmpty(ararow["voltage_level"])
  90. reuslt = append(reuslt, ararow)
  91. //}
  92. }
  93. sql := "SELECT id,(select scd_name from t_scd_scl where id=?) title,0 pid,'true' isParent,'SCL' datatype from t_scd_node_scl WHERE scd_id=? and parent_node_id=? union SELECT id,node_name title,parent_node_id pid,'false' isParent,node_name datatype from t_scd_node_scl where scd_id=? and parent_node_id=(SELECT id from t_scd_node_scl WHERE scd_id=? and parent_node_id=?) GROUP BY node_name order by id "
  94. rowset := []orm.Params{}
  95. db.Raw(sql, scdid, scdid, scdid, scdid, scdid, scdid).Values(&rowset)
  96. for _, row := range rowset {
  97. reuslt = append(reuslt, row)
  98. if tools.IsEmpty(row["title"]) == "IED" {
  99. iednodeid := tools.IsEmpty(row["id"])
  100. //添加电压等级子节点
  101. row["isParent"] = "true"
  102. sql = "select voltage_level id,t1.name title,0 pid ,'true' isParent,'voltage_level' datatype from t_substation_area t,global_const_code t1 where t.voltage_level=t1.id and scd_id=? GROUP BY voltage_level ORDER BY voltage_level"
  103. voltagelevelRowset := []orm.Params{}
  104. db.Raw(sql, scdid).Values(&voltagelevelRowset)
  105. for _, row2 := range voltagelevelRowset {
  106. row2["pid"] = iednodeid
  107. reuslt = append(reuslt, row2)
  108. }
  109. }
  110. }
  111. } else {
  112. if datatype == "area" {
  113. //当前为间隔时,则返回该间隔下的IED
  114. iedList, err := areaMgr.GetIedList(scdid, 0, int32(id), "")
  115. if err != nil {
  116. return nil, err
  117. }
  118. for _, row := range iedList {
  119. row["isParent"] = "false"
  120. row["pid"] = id
  121. row["id"] = row["node_id"]
  122. row["title"] = strings.Replace(tools.IsEmpty(row["attr_desc"]), tools.IsEmpty(row["name"]), "..", 1)
  123. row["datatype"] = "ied"
  124. }
  125. reuslt = iedList
  126. }
  127. }
  128. new(SystemLog).Success(enum.AuditType_scd_diffcompare, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, "查询IED结构树", c.Userinfo)
  129. return reuslt, nil
  130. }
  131. func (c *ScdCompare) List() ([]orm.Params, error) {
  132. db := orm.NewOrm()
  133. sql := "select t.*,t1.scd_name source_name,case when t1.enable=0 then '签入中' else t1.version end source_version ,t2.scd_name target_name,case when t2.enable=0 then '签入中' else t2.version end target_version from t_scd_diff_compare t left JOIN t_scd_scl t1 on t.source_id=t1.id left JOIN t_scd_scl t2 on t.target_id=t2.id where t.station_id=? order by CREATED_TIME desc"
  134. rowset := []orm.Params{}
  135. _, err := db.Raw(sql, c.StationId).Values(&rowset)
  136. sqllog := fmt.Sprintf("SQL:%s,参数:%+v", sql, c.StationId)
  137. if err != nil {
  138. logger.Logger.Error(err, sqllog)
  139. new(SystemLog).Fail(enum.AuditType_scd_diffcompare, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  140. } else {
  141. new(SystemLog).Success(enum.AuditType_scd_diffcompare, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  142. }
  143. return rowset, err
  144. }
  145. func (c *ScdCompare) ExpResultList(id int, nodetype string, nodeid string) ([]orm.Params, error) {
  146. db := orm.NewOrm()
  147. diffObjectTypeTransSql := `case diff_object_type when 'scd.version' then 'SCD版本号'
  148. when 'scd.crc' then 'SCD CRC'
  149. when 'scd.ied' then '装置基本信息'
  150. when 'scd.ied.Communication' then '通信接入点'
  151. when 'scd.ied.Communication.S1' then '站控层通信参数'
  152. when 'scd.ied.Communication.GSE' then 'GOOSE 通信参数'
  153. when 'scd.ied.Communication.SMV' then 'SV 通信参数'
  154. when 'scd.ied.YX' then '遥信测点'
  155. when 'scd.ied.YK' then '遥控测点'
  156. when 'scd.ied.YC' then '遥测测点'
  157. when 'scd.ied.YM' then '遥脉测点'
  158. when 'scd.ied.DZ' then '定值测点'
  159. when 'scd.ied.FCDA' then '发布虚端子'
  160. when 'scd.ied.ExtRef' then '定阅虚端子'
  161. when 'scd.ied.DatSet' then '数据集'
  162. when 'scd.ied.DatSetMeber' then '数据集'
  163. when 'scd.ied.GSEControl' then 'GOOSE控制块'
  164. when 'scd.ied.SampledValueControl' then 'SV控制块'
  165. when 'scd.ied.ReportControl' then '报告控制块'
  166. when 'scd.ied.LogControl' then '日志控制块'
  167. else '' end`
  168. sql := `select a.scd_name source_scd_name,b.scd_name target_scd_name,case when t0.diff_opt='i' then '新增' when t0.diff_opt='u' then '修改' else '删除' end opt,t0.diff_desc 'desc',ied_name,ied_desc,` + diffObjectTypeTransSql + ` diff_object_type,diff_object_name from t_scd_diff_compare t inner join t_scd_diff_compare_detail t0 on t.id=t0.compare_id left join t_scd_scl a on t.source_id=a.id left join t_scd_scl b on t.target_id=b.id where t.id=? and t0.diff_source_node_id is not null`
  169. param := []interface{}{}
  170. if nodetype == "ied" {
  171. sql = `select t.* from t_scd_diff_compare_detail t0 ,t_scd_ied_attrs s,t_scd_node_scl t1 where s.scd_id=? and s.node_id=? and t1.scd_id=? and t1.ied_name=s.attr_name and t0.diff_source_node_id=t1.id and t0.compare_id=? and t.diff_source_node_id is not null`
  172. param = append(param, nodeid)
  173. param = append(param, id)
  174. } else {
  175. param = append(param, id)
  176. }
  177. rowset := []orm.Params{}
  178. sqllog := fmt.Sprintf("SQL:%s,参数:%+v", sql+" ORDER BY t0.ied_name,t0.diff_object_type limit 0,65535", param)
  179. _, err := db.Raw(sql+" ORDER BY t0.ied_name,t0.diff_object_type limit 0,65535", param).Values(&rowset)
  180. if err != nil {
  181. logger.Logger.Error(err, sqllog)
  182. new(SystemLog).Fail(enum.AuditType_scd_diffcompare, enum.LogType_exp, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  183. } else {
  184. new(SystemLog).Success(enum.AuditType_scd_diffcompare, enum.LogType_exp, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  185. }
  186. return rowset, err
  187. }
  188. //已废弃
  189. func (c *ScdCompare) ResultList(dirction string, scdid int64, id int, nodetype, nodeid string, pageno, pagesize int) ([]orm.Params, int, error) {
  190. db := orm.NewOrm()
  191. sql := ""
  192. comp_col_name := "diff_source_node_id"
  193. if dirction == "target" {
  194. comp_col_name = "diff_object_node_id"
  195. }
  196. where := ""
  197. param := []interface{}{}
  198. if nodetype == "ied" {
  199. sql = `select t.* from t_scd_diff_compare_detail t where t.compare_id=? and EXISTS(select 1 from t_scd_node_scl where t.` + comp_col_name + `=id and ied_name=? and scd_id=?)`
  200. param = append(param, id)
  201. param = append(param, nodeid)
  202. param = append(param, scdid)
  203. } else {
  204. if nodetype != "" {
  205. sql = `select t.* from t_scd_diff_compare_detail t where t.compare_id=?`
  206. param = append(param, id)
  207. if nodetype == "area" {
  208. //间隔
  209. where += " and EXISTS(select 1 from t_area_ied_relation a,t_scd_node_scl s,t_scd_node_scl s1 where a.ied_id=s.id and s1.ied_name=s.ied_name and t." + comp_col_name + "=s1.id and a.area_id=? and s.scd_id=? and s1.scd_id=?)"
  210. param = append(param, nodeid)
  211. param = append(param, scdid)
  212. param = append(param, scdid)
  213. } else if nodetype == "voltage_level" {
  214. //电压等级
  215. where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2,t_scd_node_scl s,t_scd_node_scl s1 where v2.ied_id=s.id and s1.ied_name=s.ied_name and t." + comp_col_name + "=s1.id and v1.id=v2.area_id and v1.voltage_level=? and v1.scd_id=? and s.scd_id=? and s1.scd_id=?)"
  216. param = append(param, nodeid)
  217. param = append(param, scdid)
  218. param = append(param, scdid)
  219. param = append(param, scdid)
  220. } else if nodetype == "Communication" {
  221. //通讯类
  222. where += " and EXISTS(select 1 from t_scd_ied_node_parents_info v2 where t." + comp_col_name + "=v2.node_id and v2.path_names like ? and v2.scd_id=? )"
  223. param = append(param, "SubNetwork%")
  224. param = append(param, scdid)
  225. } else if nodetype == "DataTypeTemplates" {
  226. //通讯类
  227. where += " and EXISTS(select 1 from t_scd_ied_node_parents_info v2 where t." + comp_col_name + "=v2.node_id and v2.path_names like ? and v2.scd_id=? )"
  228. param = append(param, "DataTypeTemplates%")
  229. param = append(param, scdid)
  230. } else {
  231. //Header类
  232. where += " and t." + comp_col_name + "=?"
  233. param = append(param, nodeid)
  234. }
  235. } else {
  236. sql = `select t.* from t_scd_diff_compare_detail t,t_scd_node_scl t1 where t1.scd_id=? and t.` + comp_col_name + `=t1.id and t.compare_id=?`
  237. param = append(param, scdid)
  238. param = append(param, id)
  239. }
  240. }
  241. limit := fmt.Sprintf(" order by t.id limit %d,%d", (pageno-1)*pagesize, pagesize)
  242. rowset := []orm.Params{}
  243. sqllog := fmt.Sprintf("SQL:%s,参数:%+v", sql+where+limit, param)
  244. _, err := db.Raw(sql+where+limit, param).Values(&rowset)
  245. if err != nil {
  246. logger.Logger.Error(err, sqllog)
  247. new(SystemLog).Fail(enum.AuditType_scd_diffcompare, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  248. } else {
  249. new(SystemLog).Success(enum.AuditType_scd_diffcompare, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.Userinfo)
  250. }
  251. totalNum := 0
  252. if err == nil {
  253. tmpRowset := []orm.Params{}
  254. sql = strings.ReplaceAll(sql+where, "t.*", "count(1) cnt")
  255. sqllog = fmt.Sprintf("SQL:%s,参数:%+v", sql, param)
  256. _, err = db.Raw(sql, param).Values(&tmpRowset)
  257. if err != nil {
  258. logger.Logger.Error(err, sqllog)
  259. } else if len(tmpRowset) > 0 {
  260. for _, r1 := range tmpRowset {
  261. totalNumi, _ := strconv.Atoi(tools.IsEmpty(r1["cnt"]))
  262. totalNum += totalNumi
  263. }
  264. }
  265. }
  266. return rowset, totalNum, err
  267. }
  268. //汇总统计校验结果数量
  269. func (c *ScdCompare) SumCompareResult(compare_id int) ([]orm.Params, error) {
  270. db := orm.NewOrm()
  271. sql := `SELECT 'u' diff_opt, diff_object_type,'' ied_name,'' ied_desc,diff_desc from t_scd_diff_compare_detail t where compare_id=? and ied_name='' GROUP BY diff_object_type
  272. UNION
  273. SELECT 'i' diff_opt,'scd.ied' diff_object_type, ied_name,ied_desc ,'' diff_desc from t_scd_diff_compare_detail t where compare_id=? and ied_name=diff_object_name and diff_opt='i'
  274. UNION
  275. SELECT 'u' diff_opt,'scd.ied' diff_object_type, ied_name,ied_desc,'' diff_desc from t_scd_diff_compare_detail t where compare_id=? and diff_object_type = 'scd.ied' and ied_name=diff_object_name and diff_opt='u'
  276. UNION
  277. SELECT 'd' diff_opt,'scd.ied' diff_object_type, ied_name,ied_desc,'' diff_desc from t_scd_diff_compare_detail t where compare_id=? and diff_object_type = 'scd.ied' and ied_name=diff_object_name and diff_opt='d'
  278. union
  279. SELECT 'u' diff_opt,'scd.ied' diff_object_type, ied_name,ied_desc,'' diff_desc from t_scd_diff_compare_detail t where compare_id=? and diff_object_type like 'scd.ied.%' GROUP BY ied_name`
  280. rowset := []orm.Params{}
  281. _, err := db.Raw(sql, compare_id, compare_id, compare_id, compare_id, compare_id).Values(&rowset)
  282. if err != nil {
  283. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%d", sql, compare_id))
  284. return nil, err
  285. }
  286. return rowset, nil
  287. }
  288. //统计指定IED各分类数量
  289. func (c *ScdCompare) SumCompareTypeResult(compareId int, iedname, comptype string) (map[string]interface{}, error) {
  290. compObj := t_scd_diff_compare{Id: int64(compareId)}
  291. db := orm.NewOrm()
  292. err := db.Read(&compObj)
  293. if err != nil {
  294. logger.Logger.Error(err)
  295. return nil, err
  296. }
  297. sourceScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(compObj.SourceId))
  298. if serr != nil {
  299. return nil, serr
  300. }
  301. if sourceScdXmlObj == nil {
  302. return nil, errors.New("无效校验的源SCD,文件可能已被删除")
  303. }
  304. sourceIedObj := new(ScdNode).GetIed(sourceScdXmlObj, "", iedname)
  305. targetScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(compObj.TargetId))
  306. if serr != nil {
  307. return nil, serr
  308. }
  309. if targetScdXmlObj == nil {
  310. return nil, errors.New("无效的比对SCD,文件可能已被删除")
  311. }
  312. targetIedObj := new(ScdNode).GetIed(targetScdXmlObj, "", iedname)
  313. result := map[string]interface{}{}
  314. switch comptype {
  315. case "i":
  316. //装置基本信息
  317. result["scd.ied"] = 1
  318. break
  319. case "d":
  320. //装置基本信息
  321. result["scd.ied"] = 1
  322. break
  323. case "u":
  324. //装置基本信息
  325. num := 0
  326. if sourceIedObj.Desc != targetIedObj.Desc {
  327. num = num + 1
  328. }
  329. if sourceIedObj.Type != targetIedObj.Type {
  330. num = num + 1
  331. }
  332. if sourceIedObj.ConfigVersion != targetIedObj.ConfigVersion {
  333. num = num + 1
  334. }
  335. if sourceIedObj.Manufacturer != targetIedObj.Manufacturer {
  336. num = num + 1
  337. }
  338. if num > 0 {
  339. result["scd.ied"] = 1
  340. }
  341. sql := "select diff_object_type,count(1) cnt from t_scd_diff_compare_detail t WHERE compare_id=? and ied_name=? GROUP BY diff_object_type"
  342. rowset := []orm.Params{}
  343. _, err := db.Raw(sql, compareId, iedname).Values(&rowset)
  344. if err != nil {
  345. return nil, err
  346. }
  347. for _, r := range rowset {
  348. result[tools.IsEmpty(r["diff_object_type"])] = tools.IsEmpty(r["cnt"])
  349. }
  350. break
  351. }
  352. return result, nil
  353. }
  354. //查询IED指定差异类型的信息
  355. //compareId:比对ID
  356. //iedname:装置名称
  357. //comptype:差异类型(i\u\d)
  358. //item:比对内容项代码
  359. func (c *ScdCompare) GetCompItemDetailInfo(compareId int, iedname, comptype, itemcode string) ([]interface{}, error) {
  360. compObj := t_scd_diff_compare{Id: int64(compareId)}
  361. db := orm.NewOrm()
  362. err := db.Read(&compObj)
  363. if err != nil {
  364. logger.Logger.Error(err)
  365. return nil, err
  366. }
  367. sourceScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(compObj.SourceId))
  368. if serr != nil {
  369. return nil, serr
  370. }
  371. if sourceScdXmlObj == nil {
  372. return nil, errors.New("无效校验的源SCD,文件可能已被删除")
  373. }
  374. sourceIedObj := new(ScdNode).GetIed(sourceScdXmlObj, "", iedname)
  375. targetScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(compObj.TargetId))
  376. if serr != nil {
  377. return nil, serr
  378. }
  379. if targetScdXmlObj == nil {
  380. return nil, errors.New("无效的比对SCD,文件可能已被删除")
  381. }
  382. if itemcode == "scd.ied.Relation" {
  383. //虚回路配置
  384. scdNode := new(ScdNode)
  385. sourceRel, err1 := scdNode.GetIedInputsRelations(map[string]interface{}{
  386. "ied_name": iedname,
  387. "scd_id": compObj.SourceId,
  388. })
  389. if err1 != nil {
  390. return nil, err1
  391. }
  392. targetRel, err2 := scdNode.GetIedInputsRelations(map[string]interface{}{
  393. "ied_name": iedname,
  394. "scd_id": compObj.TargetId,
  395. })
  396. if err2 != nil {
  397. return nil, err2
  398. }
  399. iedDescMap := map[string]string{
  400. iedname: sourceIedObj.Desc,
  401. }
  402. result := []interface{}{}
  403. sourceRelMap := map[string]orm.Params{}
  404. targetRelMap := map[string]orm.Params{}
  405. for _, r := range sourceRel {
  406. sourceRelMap[fmt.Sprintf("%s%s%s", tools.IsEmpty(r["ied_name"]), tools.IsEmpty(r["ied_name"]), tools.IsEmpty(r["attr_int_addr"]), tools.IsEmpty(r["inout_type"]))] = r
  407. }
  408. for _, r := range targetRel {
  409. targetRelMap[fmt.Sprintf("%s%s%s", tools.IsEmpty(r["ied_name"]), tools.IsEmpty(r["ied_name"]), tools.IsEmpty(r["attr_int_addr"]), tools.IsEmpty(r["inout_type"]))] = r
  410. }
  411. //logger.Logger.Debug(fmt.Sprintf("sourceRelMap:%+v", sourceRelMap))
  412. //logger.Logger.Debug(fmt.Sprintf("targetRelMap:%+v", targetRelMap))
  413. for key, item := range sourceRelMap {
  414. if _, h := targetRelMap[key]; !h {
  415. //新增的端子
  416. item["opt"] = "i"
  417. tmpIedName := tools.IsEmpty(item["ied_name"])
  418. ieddesc := iedDescMap[tmpIedName]
  419. item["scd_id"] = compObj.SourceId
  420. if ieddesc != "" {
  421. item["ied_desc"] = ieddesc
  422. } else {
  423. tmpIedObj := new(ScdNode).GetIed(sourceScdXmlObj, "", tmpIedName)
  424. if tmpIedObj != nil {
  425. iedDescMap[tmpIedName] = tmpIedObj.Desc
  426. item["ied_desc"] = tmpIedObj.Desc
  427. }
  428. }
  429. result = append(result, item)
  430. }
  431. }
  432. for key, item := range targetRelMap {
  433. if _, h := sourceRelMap[key]; !h {
  434. //删除的端子
  435. item["opt"] = "d"
  436. tmpIedName := tools.IsEmpty(item["ied_name"])
  437. ieddesc := iedDescMap[tmpIedName]
  438. item["scd_id"] = compObj.TargetId
  439. if ieddesc != "" {
  440. item["ied_desc"] = ieddesc
  441. } else {
  442. tmpIedObj := new(ScdNode).GetIed(targetScdXmlObj, "", tmpIedName)
  443. if tmpIedObj != nil {
  444. iedDescMap[tmpIedName] = tmpIedObj.Desc
  445. item["ied_desc"] = tmpIedObj.Desc
  446. }
  447. }
  448. result = append(result, item)
  449. }
  450. }
  451. sourceRelMap = nil
  452. targetRelMap = nil
  453. return result, nil
  454. }
  455. targetIedObj := new(ScdNode).GetIed(targetScdXmlObj, "", iedname)
  456. result := []interface{}{}
  457. if itemcode == "scd.ied" {
  458. //IED基本信息
  459. if comptype == "i" {
  460. result = append(result, new(node_attr.BaseNode).ToMap(sourceIedObj))
  461. } else if comptype == "d" {
  462. result = append(result, new(node_attr.BaseNode).ToMap(targetIedObj))
  463. } else if comptype == "u" {
  464. result = append(result, new(node_attr.BaseNode).ToMap(sourceIedObj))
  465. result = append(result, new(node_attr.BaseNode).ToMap(targetIedObj))
  466. }
  467. } else {
  468. //需要统计新增、删除、编辑的测点
  469. sql := "SELECT diff_object_type,diff_object_name,diff_opt,diff_desc from t_scd_diff_compare_detail where compare_id=? and ied_name=? and diff_object_type=? order by diff_opt desc,diff_object_name asc"
  470. rowset := []orm.Params{}
  471. _, err := db.Raw(sql, compareId, iedname, itemcode).Values(&rowset)
  472. if err != nil {
  473. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{compareId, iedname, itemcode}))
  474. return nil, err
  475. }
  476. for _, r := range rowset {
  477. result = append(result, r)
  478. }
  479. }
  480. return result, nil
  481. }
  482. //开始比较2个文件。如果比较过程中发生错误则返回错误对象
  483. //对比结果会存储到数据表,同时以mqtt方式进行实时发布
  484. func (c *ScdCompare) Compare(oldid int) error {
  485. db := orm.NewOrm()
  486. if oldid > 0 {
  487. c.CurrCompareRecord = t_scd_diff_compare{Id: int64(oldid)}
  488. db.Read(&c.CurrCompareRecord)
  489. if c.CurrCompareRecord.NodeState == 0 {
  490. return errors.New("其他用户正在进行校验,需等待其完成!")
  491. }
  492. c.Sourceid = c.CurrCompareRecord.SourceId
  493. c.Targetid = c.CurrCompareRecord.TargetId
  494. sourceScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.Sourceid))
  495. if serr != nil {
  496. return serr
  497. }
  498. if sourceScdXmlObj == nil {
  499. return errors.New("无效校验的源SCD,文件可能已被删除")
  500. }
  501. targetScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.Targetid))
  502. if serr != nil {
  503. return serr
  504. }
  505. if targetScdXmlObj == nil {
  506. return errors.New("无效的比对SCD,文件可能已被删除")
  507. }
  508. //对原有比对进行重新比对,需要清除原有结果
  509. db.Raw("delete from t_scd_diff_compare_detail where compare_id=?", oldid).Exec()
  510. db.Raw("delete from t_scd_diff_compare_stat where compare_id=?", oldid).Exec()
  511. db.Raw("update t_scd_diff_compare set node_state=0,attr_state=0 where id=?", oldid).Exec()
  512. if c.CompareType == "SCD" {
  513. c.ScdCompare(sourceScdXmlObj, targetScdXmlObj)
  514. }
  515. return nil
  516. }
  517. if c.CompareType == "" {
  518. return errors.New("未指定校验的类型!")
  519. }
  520. if c.CompareType == "CID" {
  521. return c.CidCompare()
  522. }
  523. if c.CompareType == "CCD" {
  524. return c.CcdCompare()
  525. }
  526. if c.CompareType == "CCD_SCD" {
  527. return c.CcdScdCompare()
  528. }
  529. if c.CompareType == "CID_SCD" {
  530. return c.CidScdCompare()
  531. }
  532. if c.StationId == 0 {
  533. return errors.New("变电站ID不能为空!")
  534. }
  535. if c.Sourceid == 0 || c.Targetid == 0 {
  536. return errors.New("用于校验的源scd文件ID或目标文件ID不能为空!")
  537. }
  538. sourceScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.Sourceid))
  539. if serr != nil {
  540. return serr
  541. }
  542. if sourceScdXmlObj == nil {
  543. return errors.New("无效校验的源SCD")
  544. }
  545. targetScdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.Targetid))
  546. if serr != nil {
  547. return serr
  548. }
  549. if targetScdXmlObj == nil {
  550. return errors.New("无效的目标SCD")
  551. }
  552. //判断当前2个文件是否正在校验中
  553. sql := "select 1 from t_scd_diff_compare where source_id=? and target_id=?"
  554. rowset := []orm.Params{}
  555. _, err := db.Raw(sql, c.Sourceid, c.Targetid).Values(&rowset)
  556. if err != nil {
  557. logger.Logger.Error(err, sql)
  558. return err
  559. }
  560. if len(rowset) > 0 {
  561. //当前2个文件正在校验中或者已经有校验结果
  562. return nil
  563. }
  564. master := t_scd_diff_compare{StationId: c.StationId, FileType: c.CompareType, SourceId: c.Sourceid, SourceFile: "", TargetId: c.Targetid, TargetFile: "", NodeState: 0, AttrState: 0}
  565. master.Name = fmt.Sprintf("%s对比%s", c.CompareType, time.Now().Format("200601021504"))
  566. _, err = db.Insert(&master)
  567. if err != nil {
  568. logger.Logger.Error(err)
  569. return err
  570. }
  571. c.CurrCompareRecord = master
  572. //fmt.Println(fmt.Sprintf("==================%v", c.CurrCompareRecord))
  573. if c.CompareType == "SCD" {
  574. c.ScdCompare(sourceScdXmlObj, targetScdXmlObj)
  575. } else {
  576. return errors.New("无效的校验文件类型:" + c.CompareType)
  577. }
  578. return nil
  579. }
  580. //Scd文件节点差异对比
  581. func (c *ScdCompare) ScdCompare(sourceScdXmlObj *node_attr.SCL, targetScdXmlObj *node_attr.SCL) {
  582. go mqtt.PublishMessage("/jujutong/scd_check_tools/comp/"+fmt.Sprintf("%d", c.CurrCompareRecord.Id), `{"id":"`+fmt.Sprintf("%d", c.CurrCompareRecord.Id)+`","stationid":"`+fmt.Sprintf("%d", c.CurrCompareRecord.StationId)+`","state":0}`)
  583. t1 := time.Now().Unix()
  584. //scd版本、crc对比
  585. sourcever := ""
  586. targetver := ""
  587. detailrow := t_scd_diff_compare_detail{}
  588. if sourceScdXmlObj.Header != nil && sourceScdXmlObj.Header.History != nil && len(sourceScdXmlObj.Header.History.Hitem) > 0 {
  589. ver := sourceScdXmlObj.Header.History.Hitem[len(sourceScdXmlObj.Header.History.Hitem)-1]
  590. sourcever = ver.Version + "," + ver.Revision
  591. detailrow.SourceLineNo = sourceScdXmlObj.Header.History.Lineno
  592. detailrow.DiffSourceNodeId = sourceScdXmlObj.Header.History.NodeId
  593. }
  594. if targetScdXmlObj.Header != nil && targetScdXmlObj.Header.History != nil && len(targetScdXmlObj.Header.History.Hitem) > 0 {
  595. ver := targetScdXmlObj.Header.History.Hitem[len(targetScdXmlObj.Header.History.Hitem)-1]
  596. targetver = ver.Version + "," + ver.Revision
  597. detailrow.DiffObjectNodeId = targetScdXmlObj.Header.History.NodeId
  598. detailrow.ObjectLineNo = targetScdXmlObj.Header.History.Lineno
  599. }
  600. //logger.Logger.Debug(fmt.Sprintf("=====sourceScdXmlObj sourcever:%s targetScdXmlObj targetver:%s", sourcever, targetver))
  601. if targetver != sourcever {
  602. //scd版本差异
  603. detailrow.CompareId = c.CurrCompareRecord.Id
  604. detailrow.DiffDesc = fmt.Sprintf(`["%s","%s"]`, sourcever, targetver)
  605. detailrow.DiffObjectType = "scd.version"
  606. detailrow.DiffOpt = "u"
  607. detailrow.DiffObjectName = "version"
  608. c.CompareResultList = append(c.CompareResultList, detailrow)
  609. }
  610. //scd CRC对比
  611. sourcecrc := ""
  612. targetcrc := ""
  613. detailrow_crc := t_scd_diff_compare_detail{}
  614. if len(sourceScdXmlObj.Private) > 0 {
  615. for _, p := range sourceScdXmlObj.Private {
  616. if p.Type == "Substation virtual terminal conection CRC" {
  617. sourcecrc = p.InnerText
  618. detailrow_crc.SourceLineNo = p.Lineno
  619. detailrow_crc.DiffSourceNodeId = p.NodeId
  620. break
  621. }
  622. }
  623. }
  624. if len(targetScdXmlObj.Private) > 0 {
  625. for _, p := range targetScdXmlObj.Private {
  626. if p.Type == "Substation virtual terminal conection CRC" {
  627. targetcrc = p.InnerText
  628. detailrow_crc.ObjectLineNo = p.Lineno
  629. detailrow_crc.DiffObjectNodeId = p.NodeId
  630. break
  631. }
  632. }
  633. }
  634. //logger.Logger.Debug(fmt.Sprintf("=====sourceScdXmlObj sourcecrc:%s targetScdXmlObj targetcrc:%s", sourcecrc, targetcrc))
  635. if sourcecrc != targetcrc {
  636. //scd差异
  637. detailrow_crc.CompareId = c.CurrCompareRecord.Id
  638. detailrow_crc.DiffDesc = fmt.Sprintf(`["%s","%s"]`, sourcecrc, targetcrc)
  639. detailrow_crc.DiffObjectType = "scd.crc"
  640. detailrow_crc.DiffOpt = "u"
  641. detailrow.DiffObjectName = "crc"
  642. c.CompareResultList = append(c.CompareResultList, detailrow_crc)
  643. }
  644. //IED差异对比
  645. sourceIedlist := map[string]*node_attr.NIED{}
  646. targetIedList := map[string]*node_attr.NIED{}
  647. for _, ied := range sourceScdXmlObj.IED {
  648. sourceIedlist[ied.Name] = ied
  649. }
  650. for _, ied := range targetScdXmlObj.IED {
  651. targetIedList[ied.Name] = ied
  652. }
  653. for iedname, iedObj := range sourceIedlist {
  654. if tmpIed, h := targetIedList[iedname]; !h {
  655. //基准scd中新增了该iED
  656. c.addResult(iedname, iedObj.Desc, "i", "scd.ied", iedname, iedname, iedObj.NodeId, iedObj.Lineno)
  657. } else {
  658. sourceedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s"}`, iedObj.Desc, iedObj.Type, iedObj.Manufacturer, iedObj.ConfigVersion)
  659. targetedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s"}`, tmpIed.Desc, tmpIed.Type, tmpIed.Manufacturer, tmpIed.ConfigVersion)
  660. //编辑了ied属性
  661. if sourceedit != targetedit {
  662. desc := fmt.Sprintf(`[%s,%s]`, sourceedit, targetedit)
  663. c.addResult(iedname, iedObj.Desc, "u", "scd.ied", iedname, desc, iedObj.NodeId, iedObj.Lineno)
  664. }
  665. //比较通讯层参数:装置IP、掩码、网关
  666. c.iedCommunicationCompare(sourceScdXmlObj, targetScdXmlObj, iedname, iedObj.Desc)
  667. //比较回路虚端子配置
  668. c.iedFcdaCompare(sourceScdXmlObj, targetScdXmlObj, iedname, iedObj.Desc)
  669. }
  670. }
  671. for iedname, iedObj := range targetIedList {
  672. if _, h := sourceIedlist[iedname]; !h {
  673. //基准scd中删除了该iED
  674. c.addResult(iedname, iedObj.Desc, "d", "scd.ied", iedname, iedname, iedObj.NodeId, iedObj.Lineno)
  675. }
  676. }
  677. //差异结果写入数据库
  678. c.writeResult()
  679. c.CurrCompareRecord.NodeState = 1
  680. _, err := orm.NewOrm().Update(&c.CurrCompareRecord)
  681. if err != nil {
  682. logger.Logger.Error(err)
  683. return
  684. }
  685. t2 := time.Now().Unix()
  686. logger.Logger.Debug(fmt.Sprintf("文件差异对比完成,耗时:%d秒", t2-t1))
  687. new(SystemLog).Success(enum.AuditType_scd_diffcompare, enum.LogType_Execute, enum.OptEventType_Bus, enum.OptEventLevel_Hight, "SCD差异对比", c.Userinfo)
  688. go mqtt.PublishMessage("/jujutong/scd_check_tools/comp/"+fmt.Sprintf("%d", c.CurrCompareRecord.Id), `{"id":"`+fmt.Sprintf("%d", c.CurrCompareRecord.Id)+`","stationid":"`+fmt.Sprintf("%d", c.CurrCompareRecord.StationId)+`","state":1}`)
  689. }
  690. //CID文件节点差异对比
  691. func (c *ScdCompare) CidCompare() error {
  692. if len(c.CompFileIds) != 2 {
  693. return errors.New("CID一致性校验仅支持2个文件校验")
  694. }
  695. //根据文件id获取路径
  696. cid1id, _ := strconv.Atoi(c.CompFileIds[0])
  697. if cid1id == 0 {
  698. //非文件id时,表示是当前scd中的装置name
  699. fileinfo, _ := new(AttachmentMgr).GetInfoByIed(c.Sourceid, c.CompFileIds[0], "cid")
  700. if fileinfo.Id == 0 {
  701. return errors.New("基准CID文件ID(" + c.CompFileIds[0] + ")不正确")
  702. }
  703. cid1id = int(fileinfo.Id)
  704. }
  705. cid2id, _ := strconv.Atoi(c.CompFileIds[1])
  706. if cid2id == 0 {
  707. return errors.New("比对CID文件ID(" + c.CompFileIds[1] + ")不正确")
  708. }
  709. cidmodel := new(AttachmentMgr)
  710. cidmodel.Model.Id = int32(cid1id)
  711. cidfileobj, err := cidmodel.One()
  712. if err != nil {
  713. return err
  714. }
  715. cid1FileName := cidfileobj.FileName
  716. cid1Ct := cidfileobj.CreatedTime
  717. pathChar := string(os.PathSeparator)
  718. //解析文件为对象
  719. cid1XmlObj, err := new(ScdParse).LoadScdXml("." + strings.ReplaceAll(cidfileobj.SavePath, "\\", pathChar))
  720. if err != nil {
  721. return err
  722. }
  723. cidmodel.Model.Id = int32(cid2id)
  724. cidfileobj, err = cidmodel.One()
  725. if err != nil {
  726. return err
  727. }
  728. cid2FileName := cidfileobj.FileName
  729. cid2Ct := cidfileobj.CreatedTime
  730. cid2XmlObj, err := new(ScdParse).LoadScdXml("." + strings.ReplaceAll(cidfileobj.SavePath, "\\", pathChar))
  731. if err != nil {
  732. return err
  733. }
  734. if len(cid1XmlObj.IED) != 1 || len(cid2XmlObj.IED) != 1 {
  735. return errors.New("CID文件中的IED不正确,有且仅允许1个IED")
  736. }
  737. if cid1XmlObj.IED[0].Name != cid2XmlObj.IED[0].Name {
  738. return errors.New("两个CID文件中的IED不是同一装置,不能比对")
  739. }
  740. f1 := map[string]interface{}{"filename": cid1FileName, "ct": cid1Ct}
  741. f2 := map[string]interface{}{"filename": cid2FileName, "ct": cid2Ct}
  742. return c.cidCompe(f1, f2, cid1XmlObj, cid2XmlObj)
  743. }
  744. //CID与SCD文件节点差异对比
  745. func (c *ScdCompare) CidScdCompare() error {
  746. if len(c.CompFileIds) != 1 {
  747. return errors.New("请选择一个CID文件!")
  748. }
  749. //根据文件id获取路径
  750. if c.Sourceid == 0 {
  751. return errors.New("基准SCD文件ID(" + tools.IsEmpty(c.Sourceid) + ")不正确")
  752. }
  753. cid2id, _ := strconv.Atoi(c.CompFileIds[0])
  754. if cid2id == 0 {
  755. return errors.New("比对CID文件ID(" + c.CompFileIds[0] + ")不正确")
  756. }
  757. cidmodel := new(AttachmentMgr)
  758. cidmodel.Model.Id = int32(cid2id)
  759. cidfileobj, err := cidmodel.One()
  760. if err != nil {
  761. return err
  762. }
  763. pathChar := string(os.PathSeparator)
  764. cid2FileName := cidfileobj.FileName
  765. cid2Ct := cidfileobj.CreatedTime
  766. cid2XmlObj, err := new(ScdParse).LoadScdXml("." + strings.ReplaceAll(cidfileobj.SavePath, "\\", pathChar))
  767. if err != nil {
  768. return err
  769. }
  770. if len(cid2XmlObj.IED) != 1 {
  771. return errors.New("无效的Cid文件:" + cid2FileName)
  772. }
  773. iedname := cid2XmlObj.IED[0].Name
  774. scdinfo, _ := new(ScdMgr).One(tools.IsEmpty(c.Sourceid))
  775. if scdinfo == nil {
  776. return errors.New("无效的SCD")
  777. }
  778. //解析基准文件为对象
  779. cid1Paths := []string{".", "static", "upload", "ied", tools.IsEmpty(c.Sourceid), iedname + ".cid"}
  780. cid1Path := strings.Join(cid1Paths, pathChar)
  781. cid1Finfo, _ := os.Stat(cid1Path)
  782. if cid1Finfo == nil {
  783. return errors.New("在SCD(" + tools.IsEmpty(scdinfo["scd_name"]) + ")中未找到装置" + iedname + "的CID文件")
  784. }
  785. cid1XmlObj, err := new(ScdParse).LoadScdXml(cid1Path)
  786. if err != nil {
  787. return err
  788. }
  789. if len(cid1XmlObj.IED) != 1 || len(cid2XmlObj.IED) != 1 {
  790. return errors.New("CID文件中的IED不正确,有且仅允许1个IED")
  791. }
  792. if cid1XmlObj.IED[0].Name != cid2XmlObj.IED[0].Name {
  793. return errors.New("SCD与CID文件中的IED不是同一装置,不能比对")
  794. }
  795. f1 := map[string]interface{}{"filename": tools.IsEmpty(scdinfo["scd_name"]), "ct": tools.IsEmpty(scdinfo["CREATED_TIME"])}
  796. f2 := map[string]interface{}{"filename": cid2FileName, "ct": cid2Ct}
  797. return c.cidCompe(f1, f2, cid1XmlObj, cid2XmlObj)
  798. }
  799. func (c *ScdCompare) cidCompe(cid1info, cid2onfo map[string]interface{}, cid1XmlObj *node_attr.SCL, cid2XmlObj *node_attr.SCL) error {
  800. iedname := cid1XmlObj.IED[0].Name
  801. c.CompareBaseInfo = map[string]interface{}{}
  802. c.CompareBaseInfo["iedname"] = iedname
  803. c.CompareBaseInfo["ieddesc"] = cid1XmlObj.IED[0].Desc
  804. c.CompareBaseInfo["f1"] = cid1info
  805. c.CompareBaseInfo["f2"] = cid2onfo
  806. //对比Communication
  807. sourceedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s"}`, cid1XmlObj.IED[0].Desc, cid1XmlObj.IED[0].Type, cid1XmlObj.IED[0].Manufacturer, cid1XmlObj.IED[0].ConfigVersion)
  808. targetedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s"}`, cid2XmlObj.IED[0].Desc, cid2XmlObj.IED[0].Type, cid2XmlObj.IED[0].Manufacturer, cid2XmlObj.IED[0].ConfigVersion)
  809. //编辑了ied属性
  810. if sourceedit != targetedit {
  811. desc := fmt.Sprintf(`[%s,%s]`, sourceedit, targetedit)
  812. c.addResult(iedname, cid1XmlObj.IED[0].Desc, "u", "scd.ied", iedname, desc, 0, 0)
  813. }
  814. //比较通讯层参数:装置IP、掩码、网关
  815. c.iedCommunicationCompare(cid1XmlObj, cid2XmlObj, iedname, cid1XmlObj.IED[0].Desc)
  816. //比较回路虚端子配置
  817. c.iedFcdaCompare(cid1XmlObj, cid2XmlObj, iedname, cid2XmlObj.IED[0].Desc)
  818. return nil
  819. }
  820. //CCD文件节点差异对比
  821. func (c *ScdCompare) CcdCompare() error {
  822. if len(c.CompFileIds) != 2 {
  823. return errors.New("CCD一致性校验仅支持2个文件校验")
  824. }
  825. //根据文件id获取路径
  826. ccd1id, _ := strconv.Atoi(c.CompFileIds[0])
  827. if ccd1id == 0 {
  828. //非文件id时,表示是当前scd中的装置name
  829. fileinfo, _ := new(AttachmentMgr).GetInfoByIed(c.Sourceid, c.CompFileIds[0], "ccd")
  830. if fileinfo.Id == 0 {
  831. return errors.New("基准CCD文件ID(" + c.CompFileIds[0] + ")不正确")
  832. }
  833. ccd1id = int(fileinfo.Id)
  834. }
  835. ccd2id, _ := strconv.Atoi(c.CompFileIds[1])
  836. if ccd2id == 0 {
  837. return errors.New("比对CCD文件ID(" + c.CompFileIds[1] + ")不正确")
  838. }
  839. ccdmodel := new(AttachmentMgr)
  840. ccdmodel.Model.Id = int32(ccd1id)
  841. ccdfileobj, err := ccdmodel.One()
  842. if err != nil {
  843. return err
  844. }
  845. ccd1FileName := ccdfileobj.FileName
  846. ccd1Ct := ccdfileobj.CreatedTime
  847. pathChar := string(os.PathSeparator)
  848. //解析文件为对象
  849. ccd1XmlObj, err := new(ScdParse).LoadCcdXml("." + strings.ReplaceAll(ccdfileobj.SavePath, "\\", pathChar))
  850. if err != nil {
  851. return err
  852. }
  853. ccdmodel.Model.Id = int32(ccd2id)
  854. ccdfileobj, err = ccdmodel.One()
  855. if err != nil {
  856. return err
  857. }
  858. ccd2FileName := ccdfileobj.FileName
  859. ccd2Ct := ccdfileobj.CreatedTime
  860. //解析文件为对象
  861. ccd2XmlObj, err := new(ScdParse).LoadCcdXml("." + strings.ReplaceAll(ccdfileobj.SavePath, "\\", pathChar))
  862. if err != nil {
  863. return err
  864. }
  865. if ccd1XmlObj.Name != ccd2XmlObj.Name {
  866. return errors.New("两个CCD文件中的IED不是同一装置,不能比对")
  867. }
  868. f1 := map[string]interface{}{"filename": ccd1FileName, "ct": ccd1Ct}
  869. f2 := map[string]interface{}{"filename": ccd2FileName, "ct": ccd2Ct}
  870. return c.ccdCompe(f1, f2, ccd1XmlObj, ccd2XmlObj)
  871. }
  872. //CCD文件节点差异对比
  873. func (c *ScdCompare) CcdScdCompare() error {
  874. if len(c.CompFileIds) != 1 {
  875. return errors.New("请选择一个CCD文件!")
  876. }
  877. //根据文件id获取路径
  878. if c.Sourceid == 0 {
  879. return errors.New("基准SCD文件ID(" + tools.IsEmpty(c.Sourceid) + ")不正确")
  880. }
  881. ccd2id, _ := strconv.Atoi(c.CompFileIds[0])
  882. if ccd2id == 0 {
  883. return errors.New("比对CCD文件ID(" + c.CompFileIds[0] + ")不正确")
  884. }
  885. ccdmodel := new(AttachmentMgr)
  886. pathChar := string(os.PathSeparator)
  887. ccdmodel.Model.Id = int32(ccd2id)
  888. ccdfileobj, err := ccdmodel.One()
  889. if err != nil {
  890. return err
  891. }
  892. ccd2FileName := ccdfileobj.FileName
  893. ccd2Ct := ccdfileobj.CreatedTime
  894. //解析比对文件为对象
  895. ccd2XmlObj, err := new(ScdParse).LoadCcdXml("." + strings.ReplaceAll(ccdfileobj.SavePath, "\\", pathChar))
  896. if err != nil {
  897. return err
  898. }
  899. iedname := ccd2XmlObj.Name
  900. scdinfo, _ := new(ScdMgr).One(tools.IsEmpty(c.Sourceid))
  901. if scdinfo == nil {
  902. return errors.New("无效的SCD")
  903. }
  904. //解析基准文件为对象
  905. ccd1Paths := []string{".", "static", "upload", "ied", tools.IsEmpty(c.Sourceid), iedname + ".ccd"}
  906. ccd1Path := strings.Join(ccd1Paths, pathChar)
  907. ccd1Finfo, _ := os.Stat(ccd1Path)
  908. if ccd1Finfo == nil {
  909. return errors.New("在SCD(" + tools.IsEmpty(scdinfo["scd_name"]) + ")中未找到装置" + iedname + "的CCD文件")
  910. }
  911. ccd1XmlObj, err := new(ScdParse).LoadCcdXml(ccd1Path)
  912. if err != nil {
  913. return err
  914. }
  915. f1 := map[string]interface{}{"filename": tools.IsEmpty(scdinfo["scd_name"]), "ct": tools.IsEmpty(scdinfo["CREATED_TIME"])}
  916. f2 := map[string]interface{}{"filename": ccd2FileName, "ct": ccd2Ct}
  917. return c.ccdCompe(f1, f2, ccd1XmlObj, ccd2XmlObj)
  918. }
  919. //ccd校验
  920. func (c *ScdCompare) ccdCompe(ccd1info, ccd2onfo map[string]interface{}, ccd1XmlObj *node_attr.CcdIed, ccd2XmlObj *node_attr.CcdIed) error {
  921. iedname := ccd1XmlObj.Name
  922. c.CompareBaseInfo = map[string]interface{}{}
  923. c.CompareBaseInfo["iedname"] = iedname
  924. c.CompareBaseInfo["ieddesc"] = ccd1XmlObj.Desc
  925. c.CompareBaseInfo["f1"] = ccd1info
  926. c.CompareBaseInfo["f2"] = ccd2onfo
  927. sourceedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s","crc":"%s"}`, ccd1XmlObj.Desc, ccd1XmlObj.Type, ccd1XmlObj.Manufacturer, ccd1XmlObj.ConfigVersion, ccd1XmlObj.CRC.Id)
  928. targetedit := fmt.Sprintf(`{"desc":"%s","type":"%s","manufacturer":"%s","configVersion":"%s","crc":"%s"}`, ccd2XmlObj.Desc, ccd2XmlObj.Type, ccd2XmlObj.Manufacturer, ccd2XmlObj.ConfigVersion, ccd2XmlObj.CRC.Id)
  929. //编辑了ied属性
  930. if sourceedit != targetedit {
  931. desc := fmt.Sprintf(`[%s,%s]`, sourceedit, targetedit)
  932. c.addResult(iedname, ccd1XmlObj.Desc, "u", "scd.ied", iedname, desc, 0, 0)
  933. }
  934. sourceGoosePub := map[string]*node_attr.CcdGOCBref{}
  935. targetGoosePub := map[string]*node_attr.CcdGOCBref{}
  936. sourceGooseSub := map[string]*node_attr.CcdGOCBref{}
  937. targetGooseSub := map[string]*node_attr.CcdGOCBref{}
  938. sourceConnectedAPPub := map[string]*node_attr.NConnectedAP{}
  939. targetConnectedAPPub := map[string]*node_attr.NConnectedAP{}
  940. sourceConnectedAPSub := map[string]*node_attr.NConnectedAP{}
  941. targetConnectedAPSub := map[string]*node_attr.NConnectedAP{}
  942. sourceGooseDatsetPub := map[string]*node_attr.CcdDataSet{}
  943. targetGooseDatsetPub := map[string]*node_attr.CcdDataSet{}
  944. sourceGooseDatsetSub := map[string]*node_attr.CcdDataSet{}
  945. targetGooseDatsetSub := map[string]*node_attr.CcdDataSet{}
  946. if ccd1XmlObj.GOOSEPUB != nil {
  947. for _, item := range ccd1XmlObj.GOOSEPUB.GOCBref {
  948. sourceGoosePub[item.Name] = item
  949. if item.ConnectedAP != nil {
  950. sourceConnectedAPPub[item.GSEControl.AppID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  951. }
  952. if item.DataSet != nil {
  953. sourceGooseDatsetPub[item.GSEControl.AppID+"-"+item.DataSet.Name] = item.DataSet
  954. }
  955. }
  956. }
  957. if ccd2XmlObj.GOOSEPUB != nil {
  958. for _, item := range ccd2XmlObj.GOOSEPUB.GOCBref {
  959. targetGoosePub[item.Name] = item
  960. if item.ConnectedAP != nil {
  961. targetConnectedAPPub[item.GSEControl.AppID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  962. }
  963. if item.DataSet != nil {
  964. targetGooseDatsetPub[item.GSEControl.AppID+"-"+item.DataSet.Name] = item.DataSet
  965. }
  966. }
  967. }
  968. if ccd1XmlObj.GOOSESUB != nil {
  969. for _, item := range ccd1XmlObj.GOOSESUB.GOCBref {
  970. sourceGooseSub[item.Name] = item
  971. if item.ConnectedAP != nil {
  972. sourceConnectedAPSub[item.GSEControl.AppID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  973. }
  974. if item.DataSet != nil {
  975. sourceGooseDatsetSub[item.GSEControl.AppID+"-"+item.DataSet.Name] = item.DataSet
  976. }
  977. }
  978. }
  979. if ccd2XmlObj.GOOSESUB != nil {
  980. for _, item := range ccd2XmlObj.GOOSESUB.GOCBref {
  981. targetGooseSub[item.Name] = item
  982. targetConnectedAPSub[item.GSEControl.AppID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  983. if item.DataSet != nil {
  984. targetGooseDatsetSub[item.GSEControl.AppID+"-"+item.DataSet.Name] = item.DataSet
  985. }
  986. }
  987. }
  988. var compgoose = func(typecode string, g1, g2 map[string]*node_attr.CcdGOCBref) {
  989. for k, additem := range g1 {
  990. g2h := g2[k]
  991. if g2h == nil {
  992. //新增的
  993. desc := fmt.Sprintf(`{"appID":"%s","confRev":"%s","datSet":"%s","name":"%s","type":"%s"}`, additem.GSEControl.AppID, additem.GSEControl.ConfRev, additem.GSEControl.DatSet, additem.GSEControl.Name, additem.GSEControl.Type)
  994. c.addResult(iedname, ccd1XmlObj.Desc, "i", typecode, k, desc, 0, 0)
  995. } else {
  996. //是否有修改
  997. desc1 := fmt.Sprintf(`{"appID":"%s","confRev":"%s","datSet":"%s","name":"%s","type":"%s"}`, additem.GSEControl.AppID, additem.GSEControl.ConfRev, additem.GSEControl.DatSet, additem.GSEControl.Name, additem.GSEControl.Type)
  998. desc2 := fmt.Sprintf(`{"appID":"%s","confRev":"%s","datSet":"%s","name":"%s","type":"%s"}`, g2h.GSEControl.AppID, g2h.GSEControl.ConfRev, g2h.GSEControl.DatSet, g2h.GSEControl.Name, g2h.GSEControl.Type)
  999. if desc1 != desc2 {
  1000. c.addResult(iedname, ccd1XmlObj.Desc, "u", typecode, k, fmt.Sprintf("[%s,%s]", desc1, desc2), 0, 0)
  1001. }
  1002. }
  1003. }
  1004. for k, additem := range g2 {
  1005. if g1[k] == nil {
  1006. //删除的
  1007. desc := fmt.Sprintf(`{"appID":"%s","confRev":"%s","datSet":"%s","name":"%s","type":"%s"}`, additem.GSEControl.AppID, additem.GSEControl.ConfRev, additem.GSEControl.DatSet, additem.GSEControl.Name, additem.GSEControl.Type)
  1008. c.addResult(iedname, ccd1XmlObj.Desc, "d", typecode, k, desc, 0, 0)
  1009. }
  1010. }
  1011. }
  1012. //GOOSE发布
  1013. compgoose("scd.ied.goosepub", sourceGoosePub, targetGoosePub)
  1014. //GOOSE订阅
  1015. compgoose("scd.ied.goosesub", sourceGooseSub, targetGooseSub)
  1016. var compsv = func(typecode string, g1, g2 map[string]*node_attr.CcdSMVCBref) {
  1017. for k, additem := range g1 {
  1018. g2h := g2[k]
  1019. if g2h == nil {
  1020. //新增的
  1021. desc := fmt.Sprintf(`{"smvID":"%s","confRev":"%s","datSet":"%s","name":"%s","multicast":"%s","nofASDU":"%s","smpRate":"%s"}`, additem.SampledValueControl.SmvID, additem.SampledValueControl.ConfRev, additem.SampledValueControl.DatSet, additem.SampledValueControl.Name, additem.SampledValueControl.Multicast, additem.SampledValueControl.NofASDU, additem.SampledValueControl.SmpRate)
  1022. c.addResult(iedname, ccd1XmlObj.Desc, "i", typecode, k, desc, 0, 0)
  1023. } else {
  1024. //是否有修改
  1025. desc1 := fmt.Sprintf(`{"smvID":"%s","confRev":"%s","datSet":"%s","name":"%s","multicast":"%s","nofASDU":"%s","smpRate":"%s"}`, additem.SampledValueControl.SmvID, additem.SampledValueControl.ConfRev, additem.SampledValueControl.DatSet, additem.SampledValueControl.Name, additem.SampledValueControl.Multicast, additem.SampledValueControl.NofASDU, additem.SampledValueControl.SmpRate)
  1026. desc2 := fmt.Sprintf(`{"smvID":"%s","confRev":"%s","datSet":"%s","name":"%s","multicast":"%s","nofASDU":"%s","smpRate":"%s"}`, g2h.SampledValueControl.SmvID, g2h.SampledValueControl.ConfRev, g2h.SampledValueControl.DatSet, g2h.SampledValueControl.Name, g2h.SampledValueControl.Multicast, g2h.SampledValueControl.NofASDU, g2h.SampledValueControl.SmpRate)
  1027. if desc1 != desc2 {
  1028. c.addResult(iedname, ccd1XmlObj.Desc, "u", typecode, k, fmt.Sprintf("[%s,%s]", desc1, desc2), 0, 0)
  1029. }
  1030. }
  1031. }
  1032. for k, additem := range g2 {
  1033. if g1[k] == nil {
  1034. //删除的
  1035. desc := fmt.Sprintf(`{"smvID":"%s","confRev":"%s","datSet":"%s","name":"%s","multicast":"%s","nofASDU":"%s","smpRate":"%s"}`, additem.SampledValueControl.SmvID, additem.SampledValueControl.ConfRev, additem.SampledValueControl.DatSet, additem.SampledValueControl.Name, additem.SampledValueControl.Multicast, additem.SampledValueControl.NofASDU, additem.SampledValueControl.SmpRate)
  1036. c.addResult(iedname, ccd1XmlObj.Desc, "d", typecode, k, desc, 0, 0)
  1037. }
  1038. }
  1039. }
  1040. sourceSVPub := map[string]*node_attr.CcdSMVCBref{}
  1041. targetSVPub := map[string]*node_attr.CcdSMVCBref{}
  1042. sourceSVSub := map[string]*node_attr.CcdSMVCBref{}
  1043. targetSVSub := map[string]*node_attr.CcdSMVCBref{}
  1044. sourceSVAPPub := map[string]*node_attr.NConnectedAP{}
  1045. targetSVAPPub := map[string]*node_attr.NConnectedAP{}
  1046. sourceSVAPSub := map[string]*node_attr.NConnectedAP{}
  1047. targetSVAPSub := map[string]*node_attr.NConnectedAP{}
  1048. sourceSVDatsetPub := map[string]*node_attr.CcdDataSet{}
  1049. targetSVDatsetPub := map[string]*node_attr.CcdDataSet{}
  1050. sourceSVDatsetSub := map[string]*node_attr.CcdDataSet{}
  1051. targetSVDatsetSub := map[string]*node_attr.CcdDataSet{}
  1052. if ccd1XmlObj.SVPUB != nil {
  1053. for _, item := range ccd1XmlObj.SVPUB.SMVCBref {
  1054. sourceSVPub[item.Name] = item
  1055. if item.ConnectedAP != nil {
  1056. sourceSVAPPub[item.SampledValueControl.SmvID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  1057. }
  1058. if item.DataSet != nil {
  1059. sourceSVDatsetPub[item.SampledValueControl.SmvID+"-"+item.DataSet.Name] = item.DataSet
  1060. }
  1061. }
  1062. }
  1063. if ccd2XmlObj.SVPUB != nil {
  1064. for _, item := range ccd2XmlObj.SVPUB.SMVCBref {
  1065. targetSVPub[item.Name] = item
  1066. if item.ConnectedAP != nil {
  1067. targetSVAPPub[item.SampledValueControl.SmvID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  1068. }
  1069. if item.DataSet != nil {
  1070. targetSVDatsetPub[item.SampledValueControl.SmvID+"-"+item.DataSet.Name] = item.DataSet
  1071. }
  1072. }
  1073. }
  1074. if ccd1XmlObj.SVSUB != nil {
  1075. for _, item := range ccd1XmlObj.SVSUB.SMVCBref {
  1076. sourceSVSub[item.Name] = item
  1077. if item.ConnectedAP != nil {
  1078. sourceSVAPSub[item.SampledValueControl.SmvID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  1079. }
  1080. if item.DataSet != nil {
  1081. sourceSVDatsetSub[item.SampledValueControl.SmvID+"-"+item.DataSet.Name] = item.DataSet
  1082. }
  1083. }
  1084. }
  1085. if ccd2XmlObj.SVSUB != nil {
  1086. for _, item := range ccd2XmlObj.SVSUB.SMVCBref {
  1087. targetSVSub[item.Name] = item
  1088. if item.ConnectedAP != nil {
  1089. targetSVAPSub[item.SampledValueControl.SmvID+"-"+item.ConnectedAP.ApName] = item.ConnectedAP
  1090. }
  1091. if item.DataSet != nil {
  1092. targetSVDatsetSub[item.SampledValueControl.SmvID+"-"+item.DataSet.Name] = item.DataSet
  1093. }
  1094. }
  1095. }
  1096. //SV发布
  1097. compsv("scd.ied.svpub", sourceSVPub, targetSVPub)
  1098. //SV订阅
  1099. compsv("scd.ied.svsub", sourceSVSub, targetSVSub)
  1100. //通讯接入点比对
  1101. var compap = func(typecode string, g1, g2 map[string]*node_attr.NConnectedAP) {
  1102. ieddesc := ccd1XmlObj.Desc
  1103. for k, additem := range g1 {
  1104. g2h := g2[k]
  1105. if g2h == nil {
  1106. //新增的
  1107. desc := fmt.Sprintf(`{"apName":"%s"}`, additem.ApName)
  1108. c.addResult(iedname, ieddesc, "i", typecode, k, desc, 0, 0)
  1109. if len(additem.GSE) > 0 {
  1110. for _, item := range additem.GSE {
  1111. key := additem.ApName + "/" + item.LdInst + "/" + item.CbName
  1112. desc, _ := json.Marshal(item.Address)
  1113. c.addResult(iedname, ieddesc, "i", typecode+".GSE", key, string(desc), 0, 0)
  1114. }
  1115. }
  1116. } else {
  1117. //通讯参数对比
  1118. //GOOSE通信参数对比
  1119. sourceGse := map[string]*node_attr.NGSE{}
  1120. targetGse := map[string]*node_attr.NGSE{}
  1121. if len(additem.GSE) > 0 {
  1122. for _, item := range additem.GSE {
  1123. sourceGse[additem.ApName+"/"+item.LdInst+"/"+item.CbName] = item
  1124. }
  1125. }
  1126. if len(g2h.GSE) > 0 {
  1127. for _, item := range g2h.GSE {
  1128. targetGse[additem.ApName+"/"+item.LdInst+"/"+item.CbName] = item
  1129. }
  1130. }
  1131. //logger.Logger.Debug(fmt.Sprintf("sourceGse====:%+v", sourceGse))
  1132. //logger.Logger.Debug(fmt.Sprintf("targetGse====:%+v", targetGse))
  1133. for cbname, gse := range sourceGse {
  1134. //新增的gse
  1135. if tmpGse, h := targetGse[cbname]; !h {
  1136. desc, _ := json.Marshal(gse.Address)
  1137. c.addResult(iedname, ieddesc, "i", typecode+".GSE", cbname, string(desc), gse.NodeId, gse.Lineno)
  1138. } else {
  1139. gse1, _ := json.Marshal(gse.Address)
  1140. gse2, _ := json.Marshal(tmpGse.Address)
  1141. str1 := string(gse1)
  1142. str2 := string(gse2)
  1143. if str1 != str2 {
  1144. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1145. c.addResult(iedname, ieddesc, "u", typecode+".GSE", cbname, desc, gse.NodeId, gse.Lineno)
  1146. }
  1147. }
  1148. }
  1149. //删除的GSE
  1150. for cbname, gse := range targetGse {
  1151. if _, h := sourceGse[cbname]; !h {
  1152. desc, _ := json.Marshal(gse.Address)
  1153. c.addResult(iedname, ieddesc, "d", typecode+".GSE", cbname, string(desc), gse.NodeId, gse.Lineno)
  1154. }
  1155. }
  1156. //SV通信参数对比
  1157. sourceSmv := map[string]*node_attr.NSMV{}
  1158. targetSmv := map[string]*node_attr.NSMV{}
  1159. if len(additem.SMV) > 0 {
  1160. for _, item := range additem.SMV {
  1161. sourceSmv[additem.ApName+"/"+item.LdInst+"/"+item.CbName] = item
  1162. }
  1163. }
  1164. if len(g2h.SMV) > 0 {
  1165. for _, item := range g2h.SMV {
  1166. targetSmv[additem.ApName+"/"+item.LdInst+"/"+item.CbName] = item
  1167. }
  1168. }
  1169. for cbname, gse := range sourceSmv {
  1170. //新增的SMV
  1171. if tmpGse, h := targetSmv[cbname]; !h {
  1172. desc, _ := json.Marshal(gse.Address)
  1173. c.addResult(iedname, ieddesc, "i", typecode+".SMV", cbname, string(desc), gse.NodeId, gse.Lineno)
  1174. } else {
  1175. gse1, _ := json.Marshal(gse.Address)
  1176. gse2, _ := json.Marshal(tmpGse.Address)
  1177. str1 := string(gse1)
  1178. str2 := string(gse2)
  1179. if str1 != str2 {
  1180. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1181. c.addResult(iedname, ieddesc, "u", typecode+".SMV", cbname, (desc), gse.NodeId, gse.Lineno)
  1182. }
  1183. }
  1184. }
  1185. //删除的SMV
  1186. for cbname, gse := range targetSmv {
  1187. if _, h := sourceSmv[cbname]; !h {
  1188. desc, _ := json.Marshal(gse.Address)
  1189. c.addResult(iedname, ieddesc, "d", typecode+".SMV", cbname, string(desc), gse.NodeId, gse.Lineno)
  1190. }
  1191. }
  1192. }
  1193. }
  1194. for k, additem := range g2 {
  1195. if g1[k] == nil {
  1196. //删除的
  1197. desc := fmt.Sprintf(`{"apName":"%s"}`, additem.ApName)
  1198. c.addResult(iedname, ccd1XmlObj.Desc, "d", typecode, k, desc, 0, 0)
  1199. if len(additem.GSE) > 0 {
  1200. for _, item := range additem.GSE {
  1201. key := additem.ApName + "/" + item.LdInst + "/" + item.CbName
  1202. desc, _ := json.Marshal(item.Address)
  1203. c.addResult(iedname, ieddesc, "d", typecode+".GSE", key, string(desc), 0, 0)
  1204. }
  1205. }
  1206. }
  1207. }
  1208. }
  1209. //GOOSE发布接入点
  1210. compap("scd.ied.goosepub.Communication", sourceConnectedAPPub, targetConnectedAPPub)
  1211. //GOOSE订阅接入点
  1212. compap("scd.ied.goosesub.Communication", sourceConnectedAPSub, targetConnectedAPSub)
  1213. //SV发布接入点
  1214. compap("scd.ied.smvpub.Communication", sourceSVAPPub, targetSVAPPub)
  1215. //SV订阅接入点
  1216. compap("scd.ied.smvsub.Communication", sourceSVAPSub, targetSVAPSub)
  1217. //Dataset虚端子比对
  1218. var fcdaToJsonStr = func(fcda *node_attr.CcdFCDA) (key, jsonstr string) {
  1219. key = fmt.Sprintf("%s/%s%s", fcda.LdInst, fcda.LnClass, fcda.LnInst)
  1220. desc := ""
  1221. if len(fcda.IntAddr) > 0 {
  1222. if len(fcda.IntAddr) == 1 {
  1223. if fcda.IntAddr[0].DAI != nil {
  1224. desc = fmt.Sprintf(
  1225. `{"bType":"%s","daName":"%s","desc":"%s","doName":"%s","fc":"%s","prefix":"%s","intAddr.name":"%s","intAddr.desc":"%s","intAddr.sAddr":"%s"}`,
  1226. fcda.BType, fcda.DaName, fcda.Desc, fcda.DoName, fcda.Fc, fcda.Prefix, fcda.IntAddr[0].Name, fcda.IntAddr[0].Desc, fcda.IntAddr[0].DAI.SAddr,
  1227. )
  1228. } else {
  1229. desc = fmt.Sprintf(
  1230. `{"bType":"%s","daName":"%s","desc":"%s","doName":"%s","fc":"%s","prefix":"%s","intAddr.name":"%s","intAddr.desc":"%s"}`,
  1231. fcda.BType, fcda.DaName, fcda.Desc, fcda.DoName, fcda.Fc, fcda.Prefix, fcda.IntAddr[0].Name, fcda.IntAddr[0].Desc,
  1232. )
  1233. }
  1234. } else {
  1235. desc = fmt.Sprintf(
  1236. `{"bType":"%s","daName":"%s","desc":"%s","doName":"%s","fc":"%s","prefix":"%s",`,
  1237. fcda.BType, fcda.DaName, fcda.Desc, fcda.DoName, fcda.Fc, fcda.Prefix,
  1238. )
  1239. // 有多个intAddr
  1240. addrsList := []string{}
  1241. for i, temp := range fcda.IntAddr {
  1242. if temp.DAI == nil {
  1243. addrsList = append(addrsList, fmt.Sprintf(`"intAddr.%d.name":"%s","intAddr.%d.desc":"%s"`, i, temp.Name, temp.Desc))
  1244. } else {
  1245. addrsList = append(addrsList, fmt.Sprintf(`"intAddr.%d.name":"%s","intAddr.%d.desc":"%s","intAddr.%d.sAddr":"%s"`, i, temp.Name, temp.Desc, temp.DAI.SAddr))
  1246. }
  1247. }
  1248. desc = desc + strings.Join(addrsList, ",") + "}"
  1249. }
  1250. } else if fcda.DAI != nil {
  1251. desc = fmt.Sprintf(
  1252. `{"bType":"%s","daName":"%s","desc":"%s","doName":"%s","fc":"%s","prefix":"%s","DAI.sAddr":"%s"}`,
  1253. fcda.BType, fcda.DaName, fcda.Desc, fcda.DoName, fcda.Fc, fcda.Prefix, fcda.DAI.SAddr,
  1254. )
  1255. } else {
  1256. desc = fmt.Sprintf(
  1257. `{"bType":"%s","daName":"%s","desc":"%s","doName":"%s","fc":"%s","prefix":"%s"}`,
  1258. fcda.BType, fcda.DaName, fcda.Desc, fcda.DoName, fcda.Fc, fcda.Prefix,
  1259. )
  1260. }
  1261. return key, desc
  1262. }
  1263. var compDatset = func(typecode string, sourceDatasets, targetDatasets map[string]*node_attr.CcdDataSet) {
  1264. ieddesc := ccd1XmlObj.Desc
  1265. for key, item := range sourceDatasets {
  1266. if t2, h := targetDatasets[key]; !h {
  1267. for _, fcda := range item.FCDA {
  1268. fcdakey, fcdaStr := fcdaToJsonStr(fcda)
  1269. c.addResult(iedname, ieddesc, "i", typecode, fcdakey, fcdaStr, item.NodeId, item.Lineno)
  1270. }
  1271. } else {
  1272. //判断相同数据集中fcda是否有变化
  1273. sourceFcdaList := map[string]string{}
  1274. targetFcdaList := map[string]string{}
  1275. for _, fcda := range item.FCDA {
  1276. fcdakey, fcdaStr := fcdaToJsonStr(fcda)
  1277. sourceFcdaList[fcdakey] = fcdaStr
  1278. }
  1279. for _, fcda := range t2.FCDA {
  1280. fcdakey, fcdaStr := fcdaToJsonStr(fcda)
  1281. targetFcdaList[fcdakey] = fcdaStr
  1282. }
  1283. for skey, s1 := range sourceFcdaList {
  1284. s2, h := targetFcdaList[skey]
  1285. if !h {
  1286. c.addResult(iedname, ieddesc, "i", typecode, skey, s1, 0, 0)
  1287. } else if s1 != s2 {
  1288. c.addResult(iedname, ieddesc, "u", typecode, skey, fmt.Sprintf(`[%s,%s]`, s1, s2), 0, 0)
  1289. }
  1290. }
  1291. for skey, s1 := range targetFcdaList {
  1292. if _, h := sourceFcdaList[skey]; !h {
  1293. c.addResult(iedname, ieddesc, "d", typecode, skey, s1, 0, 0)
  1294. }
  1295. }
  1296. sourceFcdaList = nil
  1297. targetFcdaList = nil
  1298. }
  1299. }
  1300. for k, item := range targetDatasets {
  1301. if _, h := sourceDatasets[k]; !h {
  1302. for _, fcda := range item.FCDA {
  1303. fcdakey, fcdaStr := fcdaToJsonStr(fcda)
  1304. c.addResult(iedname, ieddesc, "d", typecode, fcdakey, fcdaStr, item.NodeId, item.Lineno)
  1305. }
  1306. }
  1307. }
  1308. }
  1309. //GOOSE发布虚端子
  1310. compDatset("scd.ied.goosepub.FCDA", sourceGooseDatsetPub, targetGooseDatsetPub)
  1311. //GOOSE订阅虚端子
  1312. compDatset("scd.ied.goosesub.FCDA", sourceGooseDatsetSub, targetGooseDatsetSub)
  1313. //SV发布虚端子
  1314. compDatset("scd.ied.smvpub.FCDA", sourceSVDatsetPub, targetSVDatsetPub)
  1315. //SV订阅虚端子
  1316. compDatset("scd.ied.smvsub.FCDA", sourceSVDatsetSub, targetSVDatsetSub)
  1317. return nil
  1318. }
  1319. //IED节点通信层对比。主要对比有没新增和删除:装置IP、掩码、网关等
  1320. func (c *ScdCompare) iedCommunicationCompare(sourceScdXmlObj *node_attr.SCL, targetScdXmlObj *node_attr.SCL, iedname, ieddesc string) {
  1321. sourceCommu := map[string]*node_attr.NConnectedAP{}
  1322. targetCommu := map[string]*node_attr.NConnectedAP{}
  1323. //获取基准scd中该ied的网络列表及属性
  1324. for _, net := range sourceScdXmlObj.Communication.SubNetwork {
  1325. for _, ap := range net.ConnectedAP {
  1326. if ap.IedName == iedname {
  1327. sourceCommu[fmt.Sprintf("%s:%s", net.Name, ap.ApName)] = ap
  1328. }
  1329. }
  1330. }
  1331. //获取对比scd中该ied的网络列表及属性
  1332. for _, net := range targetScdXmlObj.Communication.SubNetwork {
  1333. for _, ap := range net.ConnectedAP {
  1334. if ap.IedName == iedname {
  1335. targetCommu[fmt.Sprintf("%s:%s", net.Name, ap.ApName)] = ap
  1336. }
  1337. }
  1338. }
  1339. //对比新增的子网接入点
  1340. for key, net := range sourceCommu {
  1341. if tmpNet, h := targetCommu[key]; !h {
  1342. desc, _ := json.Marshal(net)
  1343. c.addResult(iedname, "", "i", "scd.ied.Communication", key, string(desc), net.NodeId, net.Lineno)
  1344. } else {
  1345. //对比接入点是否有更改
  1346. if net.Desc != tmpNet.Desc || net.ApName != tmpNet.ApName {
  1347. desc := fmt.Sprintf(`[{"desc":"%s","apName":"%s"},{"desc":"%s","apName":"%s"}]`, net.Desc, net.ApName, tmpNet.Desc, tmpNet.ApName)
  1348. c.addResult(iedname, ieddesc, "u", "scd.ied.Communication", key, desc, net.NodeId, net.Lineno)
  1349. }
  1350. //站控层通讯参数对比
  1351. if net.Address != nil && tmpNet.Address != nil {
  1352. address1, _ := json.Marshal(net.Address)
  1353. address2, _ := json.Marshal(tmpNet.Address)
  1354. str1 := string(address1)
  1355. str2 := string(address2)
  1356. if str1 != str2 {
  1357. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1358. c.addResult(iedname, ieddesc, "u", "scd.ied.Communication.S1", key, desc, net.NodeId, net.Lineno)
  1359. }
  1360. } else {
  1361. //对比address是否有变化
  1362. if net.Address != nil && tmpNet.Address == nil {
  1363. desc, _ := json.Marshal(net.Address)
  1364. c.addResult(iedname, ieddesc, "i", "scd.ied.Communication.S1", key, string(desc), net.NodeId, net.Lineno)
  1365. }
  1366. //对比address是否有变化
  1367. if net.Address == nil && tmpNet.Address != nil {
  1368. desc, _ := json.Marshal(tmpNet.Address)
  1369. c.addResult(iedname, ieddesc, "d", "scd.ied.Communication.S1", key, string(desc), net.NodeId, net.Lineno)
  1370. }
  1371. }
  1372. //GOOSE通信参数对比
  1373. sourceGse := map[string]*node_attr.NGSE{}
  1374. targetGse := map[string]*node_attr.NGSE{}
  1375. if len(net.GSE) > 0 {
  1376. for _, item := range net.GSE {
  1377. sourceGse[item.CbName] = item
  1378. }
  1379. }
  1380. if len(tmpNet.GSE) > 0 {
  1381. for _, item := range tmpNet.GSE {
  1382. targetGse[item.CbName] = item
  1383. }
  1384. }
  1385. for cbname, gse := range sourceGse {
  1386. //新增的gse
  1387. if tmpGse, h := targetGse[cbname]; !h {
  1388. desc, _ := json.Marshal(gse)
  1389. c.addResult(iedname, ieddesc, "i", "scd.ied.Communication.GSE", cbname, string(desc), gse.NodeId, gse.Lineno)
  1390. } else {
  1391. gse1, _ := json.Marshal(gse)
  1392. gse2, _ := json.Marshal(tmpGse)
  1393. str1 := string(gse1)
  1394. str2 := string(gse2)
  1395. if str1 != str2 {
  1396. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1397. c.addResult(iedname, ieddesc, "u", "scd.ied.Communication.GSE", cbname, desc, gse.NodeId, gse.Lineno)
  1398. }
  1399. }
  1400. }
  1401. //删除的GSE
  1402. for cbname, gse := range targetGse {
  1403. if _, h := sourceGse[cbname]; !h {
  1404. desc, _ := json.Marshal(gse)
  1405. c.addResult(iedname, ieddesc, "d", "scd.ied.Communication.GSE", cbname, string(desc), gse.NodeId, gse.Lineno)
  1406. }
  1407. }
  1408. //SV通信参数对比
  1409. sourceSmv := map[string]*node_attr.NSMV{}
  1410. targetSmv := map[string]*node_attr.NSMV{}
  1411. if len(net.SMV) > 0 {
  1412. for _, item := range net.SMV {
  1413. sourceSmv[item.CbName] = item
  1414. }
  1415. }
  1416. if len(tmpNet.SMV) > 0 {
  1417. for _, item := range tmpNet.SMV {
  1418. targetSmv[item.CbName] = item
  1419. }
  1420. }
  1421. for cbname, gse := range sourceSmv {
  1422. //新增的SMV
  1423. if tmpGse, h := targetSmv[cbname]; !h {
  1424. desc, _ := json.Marshal(gse)
  1425. c.addResult(iedname, ieddesc, "i", "scd.ied.Communication.SMV", cbname, string(desc), gse.NodeId, gse.Lineno)
  1426. } else {
  1427. gse1, _ := json.Marshal(gse)
  1428. gse2, _ := json.Marshal(tmpGse)
  1429. str1 := string(gse1)
  1430. str2 := string(gse2)
  1431. if str1 != str2 {
  1432. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1433. c.addResult(iedname, ieddesc, "u", "scd.ied.Communication.SMV", cbname, (desc), gse.NodeId, gse.Lineno)
  1434. }
  1435. }
  1436. }
  1437. //删除的SMV
  1438. for cbname, gse := range targetSmv {
  1439. if _, h := sourceSmv[cbname]; !h {
  1440. desc, _ := json.Marshal(gse)
  1441. c.addResult(iedname, ieddesc, "d", "scd.ied.Communication.SMV", cbname, string(desc), gse.NodeId, gse.Lineno)
  1442. }
  1443. }
  1444. }
  1445. }
  1446. //对比删除的接入点
  1447. for key, net := range targetCommu {
  1448. if _, h := sourceCommu[key]; !h {
  1449. desc, _ := json.Marshal(net)
  1450. c.addResult(iedname, ieddesc, "d", "scd.ied.Communication", key, string(desc), net.NodeId, net.Lineno)
  1451. }
  1452. }
  1453. }
  1454. //IED回路虚端子配置及控制块、测点信息对比
  1455. func (c *ScdCompare) iedFcdaCompare(sourceScdXmlObj *node_attr.SCL, targetScdXmlObj *node_attr.SCL, iedname, ieddesc string) {
  1456. //Goose及SV控制块提取
  1457. sourceGooseBlock := map[string]*node_attr.NGSEControl{}
  1458. sourceSvBlock := map[string]*node_attr.NSampledValueControl{}
  1459. targetGooseBlock := map[string]*node_attr.NGSEControl{}
  1460. targetSvBlock := map[string]*node_attr.NSampledValueControl{}
  1461. sourceIedObj := new(ScdNode).GetIed(sourceScdXmlObj, "", iedname)
  1462. targetIedObj := new(ScdNode).GetIed(targetScdXmlObj, "", iedname)
  1463. sourcePublishFcda := map[string]*node_attr.NFCDA{} //发布虚端子
  1464. targetPublishFcda := map[string]*node_attr.NFCDA{} //发布虚端子
  1465. sourceSubExtref := map[string]*node_attr.NExtRef{} //订阅虚端子
  1466. targetSubExtref := map[string]*node_attr.NExtRef{} //订阅虚端子
  1467. sourceReportControl := map[string]*node_attr.NReportControl{}
  1468. targetReportControl := map[string]*node_attr.NReportControl{}
  1469. sourceLogControl := map[string]*node_attr.NLogControl{}
  1470. targetLogControl := map[string]*node_attr.NLogControl{}
  1471. //比较IED内的遥控是否存在新增、删除、变动
  1472. sourceYaoKongDoiList := new(ScdMgr).GetYaoKongDOIMap(sourceScdXmlObj, iedname)
  1473. targetYaoKongDoiList := new(ScdMgr).GetYaoKongDOIMap(targetScdXmlObj, iedname)
  1474. //比较IED内的定值是否存在新增、删除、变动
  1475. sourceDingZhiDoiList := new(ScdMgr).GetDingZhiDOIMap(sourceScdXmlObj, iedname)
  1476. targetDingZhiDoiList := new(ScdMgr).GetDingZhiDOIMap(targetScdXmlObj, iedname)
  1477. //比较IED内的遥信是否存在新增、删除、变动
  1478. sourceYaoCe, sourceYaoXin, sourceYaoMai := new(ScdMgr).GetYcYkYmMap(sourceScdXmlObj, iedname)
  1479. targetYaoCe, targetYaoXin, targetYaoMai := new(ScdMgr).GetYcYkYmMap(targetScdXmlObj, iedname)
  1480. //数据集及成员
  1481. sourceDatasets := map[string]*node_attr.NDataSet{}
  1482. targetDatasets := map[string]*node_attr.NDataSet{}
  1483. for k, item := range sourceYaoKongDoiList {
  1484. if tempItem, h := targetYaoKongDoiList[k]; !h {
  1485. desc, _ := json.Marshal(item)
  1486. c.addResult(iedname, ieddesc, "i", "scd.ied.YK", k, string(desc), item.NodeId, item.Lineno)
  1487. } else {
  1488. bye1, _ := json.Marshal(item)
  1489. bye2, _ := json.Marshal(tempItem)
  1490. str1 := string(bye1)
  1491. str2 := string(bye2)
  1492. if str1 != str2 {
  1493. logger.Logger.Debug(fmt.Sprintf("发现遥控测点有更改,byte1:%+v byte2:%+v", bye1, bye2))
  1494. desc := fmt.Sprintf(`[%s,%s]`, (str1), (str2))
  1495. c.addResult(iedname, ieddesc, "u", "scd.ied.YK", k, desc, item.NodeId, item.Lineno)
  1496. }
  1497. }
  1498. }
  1499. for k, item := range targetYaoKongDoiList {
  1500. if _, h := sourceYaoKongDoiList[k]; !h {
  1501. desc, _ := json.Marshal(item)
  1502. c.addResult(iedname, ieddesc, "d", "scd.ied.YK", k, string(desc), item.NodeId, item.Lineno)
  1503. }
  1504. }
  1505. for k, item := range sourceDingZhiDoiList {
  1506. if tempItem, h := targetDingZhiDoiList[k]; !h {
  1507. desc, _ := json.Marshal(item)
  1508. c.addResult(iedname, ieddesc, "i", "scd.ied.DZ", k, string(desc), item.NodeId, item.Lineno)
  1509. } else {
  1510. bye1, _ := json.Marshal(item)
  1511. bye2, _ := json.Marshal(tempItem)
  1512. str1 := string(bye1)
  1513. str2 := string(bye2)
  1514. if str1 != str2 {
  1515. desc := fmt.Sprintf(`[%s,%s]`, (str1), (str2))
  1516. c.addResult(iedname, ieddesc, "u", "scd.ied.DZ", k, desc, item.NodeId, item.Lineno)
  1517. }
  1518. }
  1519. }
  1520. for k, item := range targetDingZhiDoiList {
  1521. if _, h := sourceDingZhiDoiList[k]; !h {
  1522. desc, _ := json.Marshal(item)
  1523. c.addResult(iedname, ieddesc, "d", "scd.ied.DZ", k, string(desc), item.NodeId, item.Lineno)
  1524. }
  1525. }
  1526. for _, ap := range sourceIedObj.AccessPoint {
  1527. if ap.Server == nil {
  1528. continue
  1529. }
  1530. for _, ld := range ap.Server.LDevice {
  1531. if ld.LN0 == nil {
  1532. break
  1533. }
  1534. for _, goose := range ld.LN0.GSEControl {
  1535. sourceGooseBlock[ld.Inst+"."+goose.Name] = goose
  1536. }
  1537. for _, smv := range ld.LN0.SampledValueControl {
  1538. sourceSvBlock[ld.Inst+"."+smv.Name] = smv
  1539. }
  1540. //发布虚端子列表
  1541. for _, dst := range ld.LN0.DataSet {
  1542. sourceDatasets[ld.Inst+"."+dst.Name] = dst
  1543. for _, fcda := range dst.FCDA {
  1544. key := fmt.Sprintf("%s/%s%s%s.%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.DaName)
  1545. sourcePublishFcda[key] = fcda
  1546. }
  1547. }
  1548. //订阅虚端子
  1549. if ld.LN0.Inputs != nil {
  1550. for _, extref := range ld.LN0.Inputs.ExtRef {
  1551. sourceSubExtref[extref.IntAddr] = extref
  1552. }
  1553. }
  1554. //报告控制块
  1555. for _, rpb := range ld.LN0.ReportControl {
  1556. sourceReportControl[ld.Inst+rpb.Name] = rpb
  1557. }
  1558. //日志控制块
  1559. for _, rpb := range ld.LN0.LogControl {
  1560. sourceLogControl[ld.Inst+rpb.Name] = rpb
  1561. }
  1562. }
  1563. }
  1564. for _, ap := range targetIedObj.AccessPoint {
  1565. if ap.Server == nil {
  1566. continue
  1567. }
  1568. for _, ld := range ap.Server.LDevice {
  1569. if ld.LN0 == nil {
  1570. break
  1571. }
  1572. for _, goose := range ld.LN0.GSEControl {
  1573. targetGooseBlock[ld.Inst+"."+goose.Name] = goose
  1574. }
  1575. for _, smv := range ld.LN0.SampledValueControl {
  1576. targetSvBlock[ld.Inst+"."+smv.Name] = smv
  1577. }
  1578. //发布虚端子列表
  1579. for _, dst := range ld.LN0.DataSet {
  1580. targetDatasets[ld.Inst+"."+dst.Name] = dst
  1581. for _, fcda := range dst.FCDA {
  1582. key := fmt.Sprintf("%s/%s%s%s.%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.DaName)
  1583. targetPublishFcda[key] = fcda
  1584. }
  1585. }
  1586. //订阅虚端子
  1587. if ld.LN0.Inputs != nil {
  1588. for _, extref := range ld.LN0.Inputs.ExtRef {
  1589. targetSubExtref[extref.IntAddr] = extref
  1590. }
  1591. }
  1592. //报告控制块
  1593. for _, rpb := range ld.LN0.ReportControl {
  1594. targetReportControl[ld.Inst+rpb.Name] = rpb
  1595. }
  1596. //日志控制块
  1597. for _, rpb := range ld.LN0.LogControl {
  1598. targetLogControl[ld.Inst+rpb.Name] = rpb
  1599. }
  1600. }
  1601. }
  1602. //GOOSE控制块
  1603. for blockkey, item := range sourceGooseBlock {
  1604. if tmpItem, h := targetGooseBlock[blockkey]; !h {
  1605. //新增了控制块
  1606. desc, _ := json.Marshal(item)
  1607. c.addResult(iedname, ieddesc, "i", "scd.ied.GSEControl", blockkey, string(desc), item.NodeId, item.Lineno)
  1608. } else {
  1609. b1, _ := json.Marshal(item)
  1610. b2, _ := json.Marshal(tmpItem)
  1611. //块参数是否更改
  1612. paraSource := string(b1)
  1613. paraTarget := string(b2)
  1614. if paraSource != paraTarget {
  1615. desc := fmt.Sprintf(`[%s,%s]`, paraSource, paraTarget)
  1616. c.addResult(iedname, ieddesc, "u", "scd.ied.GSEControl", blockkey, desc, item.NodeId, item.Lineno)
  1617. }
  1618. }
  1619. }
  1620. for blockkey, item := range targetGooseBlock {
  1621. if _, h := sourceGooseBlock[blockkey]; !h {
  1622. //删除了控制块
  1623. desc, _ := json.Marshal(item)
  1624. c.addResult(iedname, ieddesc, "d", "scd.ied.GSEControl", blockkey, string(desc), item.NodeId, item.Lineno)
  1625. }
  1626. }
  1627. //SV控制块
  1628. for blockkey, item := range sourceSvBlock {
  1629. if tmpItem, h := targetSvBlock[blockkey]; !h {
  1630. //新增了控制块
  1631. desc, _ := json.Marshal(item)
  1632. c.addResult(iedname, ieddesc, "i", "scd.ied.SampledValueControl", blockkey, string(desc), item.NodeId, item.Lineno)
  1633. } else {
  1634. b1, _ := json.Marshal(item)
  1635. b2, _ := json.Marshal(tmpItem)
  1636. //块参数是否更改
  1637. paraSource := string(b1)
  1638. paraTarget := string(b2)
  1639. if paraSource != paraTarget {
  1640. desc := fmt.Sprintf(`[%s,%s]`, paraSource, paraTarget)
  1641. c.addResult(iedname, ieddesc, "u", "scd.ied.SampledValueControl", blockkey, desc, item.NodeId, item.Lineno)
  1642. }
  1643. }
  1644. }
  1645. for blockkey, item := range targetGooseBlock {
  1646. if _, h := sourceGooseBlock[blockkey]; !h {
  1647. //删除了控制块
  1648. desc, _ := json.Marshal(item)
  1649. c.addResult(iedname, ieddesc, "d", "scd.ied.SampledValueControl", blockkey, string(desc), item.NodeId, item.Lineno)
  1650. }
  1651. }
  1652. //控制块及发布虚端子对比
  1653. for key, item := range sourcePublishFcda {
  1654. //新增的发布虚端子
  1655. if _, h := targetPublishFcda[key]; !h {
  1656. desc, _ := json.Marshal(item)
  1657. c.addResult(iedname, ieddesc, "i", "scd.ied.FCDA", key, string(desc), item.NodeId, item.Lineno)
  1658. //发布虚端子同时也是数据集成员
  1659. c.addResult(iedname, ieddesc, "i", "scd.ied.DatSetMeber", key, string(desc), item.NodeId, item.Lineno)
  1660. }
  1661. }
  1662. for key, item := range targetPublishFcda {
  1663. //删除的发布虚端子
  1664. if _, h := sourcePublishFcda[key]; !h {
  1665. desc, _ := json.Marshal(item)
  1666. c.addResult(iedname, ieddesc, "d", "scd.ied.FCDA", key, string(desc), item.NodeId, item.Lineno)
  1667. //发布虚端子同时也是数据集成员
  1668. c.addResult(iedname, ieddesc, "d", "scd.ied.DatSetMeber", key, string(desc), item.NodeId, item.Lineno)
  1669. }
  1670. }
  1671. //控制块及订阅虚端子对比
  1672. for key, item := range sourceSubExtref {
  1673. //新增的订阅虚端子
  1674. if _, h := targetSubExtref[key]; !h {
  1675. desc, _ := json.Marshal(item)
  1676. c.addResult(iedname, ieddesc, "i", "scd.ied.ExtRef", key, string(desc), item.NodeId, item.Lineno)
  1677. }
  1678. }
  1679. for key, item := range targetSubExtref {
  1680. //删除的订阅虚端子
  1681. if _, h := sourceSubExtref[key]; !h {
  1682. desc, _ := json.Marshal(item)
  1683. c.addResult(iedname, ieddesc, "d", "scd.ied.ExtRef", key, string(desc), item.NodeId, item.Lineno)
  1684. }
  1685. }
  1686. //报告控制块
  1687. for key, item := range sourceReportControl {
  1688. if tmpItem, h := targetReportControl[key]; !h {
  1689. desc, _ := json.Marshal(item)
  1690. c.addResult(iedname, ieddesc, "i", "scd.ied.ReportControl", key, string(desc), item.NodeId, item.Lineno)
  1691. } else {
  1692. //判断是否更改
  1693. b1, _ := json.Marshal(item)
  1694. b2, _ := json.Marshal(tmpItem)
  1695. paraSource := string(b1)
  1696. paraTarget := string(b2)
  1697. if paraSource != paraTarget {
  1698. desc := fmt.Sprintf(`[%s,%s]`, paraSource, paraTarget)
  1699. c.addResult(iedname, ieddesc, "u", "scd.ied.ReportControl", key, desc, item.NodeId, item.Lineno)
  1700. }
  1701. }
  1702. }
  1703. for key, item := range targetReportControl {
  1704. if _, h := sourceReportControl[key]; !h {
  1705. desc, _ := json.Marshal(item)
  1706. c.addResult(iedname, ieddesc, "d", "scd.ied.ReportControl", key, string(desc), item.NodeId, item.Lineno)
  1707. }
  1708. }
  1709. //日志控制块
  1710. for key, item := range sourceLogControl {
  1711. if tmpItem, h := targetLogControl[key]; !h {
  1712. desc, _ := json.Marshal(item)
  1713. c.addResult(iedname, ieddesc, "i", "scd.ied.LogControl", key, string(desc), item.NodeId, item.Lineno)
  1714. } else {
  1715. //判断是否更改
  1716. b1, _ := json.Marshal(item)
  1717. b2, _ := json.Marshal(tmpItem)
  1718. paraSource := string(b1)
  1719. paraTarget := string(b2)
  1720. if paraSource != paraTarget {
  1721. desc := fmt.Sprintf(`[%s,%s]`, paraSource, paraTarget)
  1722. c.addResult(iedname, ieddesc, "u", "scd.ied.LogControl", key, desc, item.NodeId, item.Lineno)
  1723. }
  1724. }
  1725. }
  1726. for key, item := range targetLogControl {
  1727. if _, h := sourceLogControl[key]; !h {
  1728. desc, _ := json.Marshal(item)
  1729. c.addResult(iedname, ieddesc, "d", "scd.ied.LogControl", key, string(desc), item.NodeId, item.Lineno)
  1730. }
  1731. }
  1732. //遥测对比
  1733. for k, item := range sourceYaoCe {
  1734. if tempitem, h := targetYaoCe[k]; !h {
  1735. desc, _ := json.Marshal(item)
  1736. c.addResult(iedname, ieddesc, "i", "scd.ied.YC", k, string(desc), int64(0), int64(0))
  1737. } else {
  1738. b1, _ := json.Marshal(item)
  1739. b2, _ := json.Marshal(tempitem)
  1740. str1 := string(b1)
  1741. str2 := string(b2)
  1742. if str1 != str2 {
  1743. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1744. c.addResult(iedname, ieddesc, "u", "scd.ied.YC", k, desc, int64(0), int64(0))
  1745. }
  1746. }
  1747. }
  1748. for k, item := range targetYaoCe {
  1749. if _, h := sourceYaoCe[k]; !h {
  1750. desc, _ := json.Marshal(item)
  1751. c.addResult(iedname, ieddesc, "d", "scd.ied.YC", k, string(desc), int64(0), int64(0))
  1752. }
  1753. }
  1754. //遥信测点对比
  1755. for k, item := range sourceYaoXin {
  1756. if tempitem, h := targetYaoXin[k]; !h {
  1757. desc, _ := json.Marshal(item)
  1758. c.addResult(iedname, ieddesc, "i", "scd.ied.YX", k, string(desc), int64(0), int64(0))
  1759. } else {
  1760. b1, _ := json.Marshal(item)
  1761. b2, _ := json.Marshal(tempitem)
  1762. str1 := string(b1)
  1763. str2 := string(b2)
  1764. if str1 != str2 {
  1765. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1766. c.addResult(iedname, ieddesc, "u", "scd.ied.YX", k, desc, int64(0), int64(0))
  1767. }
  1768. }
  1769. }
  1770. for k, item := range targetYaoXin {
  1771. if _, h := sourceYaoXin[k]; !h {
  1772. desc, _ := json.Marshal(item)
  1773. c.addResult(iedname, ieddesc, "d", "scd.ied.YX", k, string(desc), int64(0), int64(0))
  1774. }
  1775. }
  1776. //遥脉测点对比
  1777. for k, item := range sourceYaoMai {
  1778. if tempitem, h := targetYaoMai[k]; !h {
  1779. desc, _ := json.Marshal(item)
  1780. c.addResult(iedname, ieddesc, "i", "scd.ied.YM", k, string(desc), int64(0), int64(0))
  1781. } else {
  1782. b1, _ := json.Marshal(item)
  1783. b2, _ := json.Marshal(tempitem)
  1784. str1 := string(b1)
  1785. str2 := string(b2)
  1786. if str1 != str2 {
  1787. desc := fmt.Sprintf(`[%s,%s]`, str1, str2)
  1788. c.addResult(iedname, ieddesc, "u", "scd.ied.YM", k, desc, int64(0), int64(0))
  1789. }
  1790. }
  1791. }
  1792. for k, item := range targetYaoMai {
  1793. if _, h := sourceYaoMai[k]; !h {
  1794. desc, _ := json.Marshal(item)
  1795. c.addResult(iedname, ieddesc, "d", "scd.ied.YM", k, string(desc), int64(0), int64(0))
  1796. }
  1797. }
  1798. //数据集对比
  1799. for key, item := range sourceDatasets {
  1800. if tempitem, h := targetDatasets[key]; !h {
  1801. desc := fmt.Sprintf(`{"desc":"%s","name":"%s"}`, item.Desc, item.Name)
  1802. c.addResult(iedname, ieddesc, "i", "scd.ied.DataSet", key, desc, item.NodeId, item.Lineno)
  1803. } else {
  1804. b1 := fmt.Sprintf(`{"desc":"%s","name":"%s"}`, item.Desc, item.Name)
  1805. b2 := fmt.Sprintf(`{"desc":"%s","name":"%s"}`, tempitem.Desc, tempitem.Name)
  1806. if b1 != b2 {
  1807. desc := fmt.Sprintf(`[%s,%s]`, b1, b2)
  1808. c.addResult(iedname, ieddesc, "u", "scd.ied.DataSet", key, desc, int64(0), int64(0))
  1809. }
  1810. }
  1811. }
  1812. for k, item := range targetDatasets {
  1813. if _, h := sourceDatasets[k]; !h {
  1814. desc := fmt.Sprintf(`{"desc":"%s","name":"%s"}`, item.Desc, item.Name)
  1815. c.addResult(iedname, ieddesc, "d", "scd.ied.DataSet", k, desc, item.NodeId, item.Lineno)
  1816. }
  1817. }
  1818. sourceGooseBlock = nil
  1819. sourceSvBlock = nil
  1820. targetGooseBlock = nil
  1821. targetSvBlock = nil
  1822. sourceIedObj = nil
  1823. targetIedObj = nil
  1824. sourcePublishFcda = nil
  1825. targetPublishFcda = nil
  1826. sourceSubExtref = nil
  1827. targetSubExtref = nil
  1828. sourceReportControl = nil
  1829. targetReportControl = nil
  1830. sourceLogControl = nil
  1831. targetLogControl = nil
  1832. sourceYaoXin = nil
  1833. targetYaoXin = nil
  1834. sourceYaoKongDoiList = nil
  1835. targetYaoKongDoiList = nil
  1836. sourceYaoCe = nil
  1837. targetYaoCe = nil
  1838. sourceYaoMai = nil
  1839. targetYaoMai = nil
  1840. sourceDingZhiDoiList = nil
  1841. targetDingZhiDoiList = nil
  1842. }
  1843. func (c *ScdCompare) addResult(iedname, ieddesc, opt, objtype, objname, desc string, nodeid, lineno int64) {
  1844. detailrow := t_scd_diff_compare_detail{}
  1845. detailrow.CompareId = c.CurrCompareRecord.Id
  1846. detailrow.DiffDesc = desc
  1847. detailrow.DiffObjectType = objtype
  1848. detailrow.DiffOpt = opt
  1849. detailrow.IedName = iedname
  1850. detailrow.IedDesc = ieddesc
  1851. detailrow.DiffObjectName = objname
  1852. detailrow.DiffObjectNodeId = nodeid
  1853. detailrow.ObjectLineNo = lineno
  1854. c.CompareResultList = append(c.CompareResultList, detailrow)
  1855. }
  1856. //将对比结果批量写入数据库
  1857. func (c *ScdCompare) writeResult() {
  1858. if len(c.CompareResultList) == 0 {
  1859. return
  1860. }
  1861. db := orm.NewOrm()
  1862. nodeCols := "(compare_id,diff_object_type,diff_object_node_id,diff_object_name,diff_opt,diff_desc,diff_source_node_id,source_line_no,object_line_no,ied_name,ied_desc)"
  1863. loadedRec := 0
  1864. nodeSqlValuesAry := []string{}
  1865. c.lock.Lock()
  1866. compareId := int64(0)
  1867. for _, m := range c.CompareResultList {
  1868. if compareId == 0 {
  1869. compareId = m.CompareId
  1870. }
  1871. nodeSqlValuesAry = append(nodeSqlValuesAry, fmt.Sprintf("(%d,'%s',%d,'%s','%s','%s',%d,%d,%d,'%s','%s')", m.CompareId, m.DiffObjectType, m.DiffObjectNodeId, m.DiffObjectName, m.DiffOpt, m.DiffDesc, m.DiffSourceNodeId, m.SourceLineNo, m.ObjectLineNo, m.IedName, m.IedDesc))
  1872. if len(nodeSqlValuesAry) == 1000 {
  1873. sql := "insert into t_scd_diff_compare_detail" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  1874. _, err := db.Raw(sql).Exec()
  1875. if err != nil {
  1876. logger.Logger.Error(err)
  1877. }
  1878. loadedRec = loadedRec + 1000
  1879. nodeSqlValuesAry = nil
  1880. nodeSqlValuesAry = []string{}
  1881. }
  1882. }
  1883. if len(nodeSqlValuesAry) > 0 {
  1884. sql := "insert into t_scd_diff_compare_detail" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  1885. _, err := db.Raw(sql).Exec()
  1886. if err != nil {
  1887. logger.Logger.Error(err, sql)
  1888. }
  1889. nodeSqlValuesAry = nil
  1890. }
  1891. c.CompareResultList = nil
  1892. c.lock.Unlock()
  1893. runtime.GC()
  1894. }