scd_diff_compare.go 74 KB

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