scd_area.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. package bo
  2. import (
  3. "scd_check_tools/logger"
  4. "scd_check_tools/models/enum"
  5. "scd_check_tools/models/node_attr"
  6. "scd_check_tools/tools"
  7. "errors"
  8. "fmt"
  9. "log"
  10. "regexp"
  11. "strconv"
  12. "strings"
  13. "sync"
  14. "github.com/astaxie/beego/orm"
  15. )
  16. //SCD间隔管理
  17. type ScdAreaMgr struct {
  18. DeviceBaseModel
  19. //SCD文件ID
  20. ScdId int64
  21. //电压等级定义
  22. VoltageLevelDef map[string]int32
  23. //设备类型定义
  24. DeviceTypeDef map[string]int
  25. CacheAreaID map[string]int32
  26. CacheAreaIDByIedNameNo map[string]int32
  27. CacheLock sync.RWMutex
  28. }
  29. type T_substation_area struct {
  30. Id int64 `orm:"pk"`
  31. Name string
  32. NameNo string
  33. ScdId int64
  34. VoltageLevel int32
  35. DispatchNo string
  36. SubstationId int
  37. CreatedBy int
  38. CreatedTime string
  39. }
  40. type t_area_ied_relation struct {
  41. Id int32 `orm:"pk"`
  42. AreaId int32
  43. IedId int64
  44. IedName string
  45. IedType string
  46. ScdId int64
  47. }
  48. // 其他非标准装置列表。通过系统参数OtherIedNameList维护
  49. var otherIedNameList map[string]bool
  50. func init() {
  51. orm.RegisterModel(new(T_substation_area))
  52. orm.RegisterModel(new(t_area_ied_relation))
  53. }
  54. func (c *ScdAreaMgr) Init(scdid int64) {
  55. c.VoltageLevelDef = map[string]int32{}
  56. c.DeviceTypeDef = map[string]int{}
  57. c.CacheAreaIDByIedNameNo = map[string]int32{}
  58. c.CacheAreaID = map[string]int32{}
  59. c.CacheLock = sync.RWMutex{}
  60. db := orm.NewOrm()
  61. rowset := []orm.Params{}
  62. db.Raw("select * from global_const_code where parentcode=?", "voltage_level").Values(&rowset)
  63. for _, row := range rowset {
  64. vl := strings.ToLower(tools.IsEmpty(row["name"]))
  65. id, _ := strconv.ParseInt(tools.IsEmpty(row["id"]), 10, 32)
  66. c.VoltageLevelDef[vl] = int32(id)
  67. }
  68. db.Raw("select * from global_const_code where parentcode=?", "device_type").Values(&rowset)
  69. for _, row := range rowset {
  70. vl := tools.IsEmpty(row["code"])
  71. c.DeviceTypeDef[vl] = 1
  72. }
  73. v, _ := GetSysParamValue("OtherIedNameList", "")
  74. otherIedNameList = map[string]bool{}
  75. if v != "" {
  76. vs := strings.Split(v, ",")
  77. for _, vv := range vs {
  78. otherIedNameList[vv] = true
  79. }
  80. }
  81. }
  82. //保存指定间隔所属的电压等级
  83. func (c *ScdAreaMgr) SetVoltageLevel(id string, voltagelavel int) error {
  84. db := orm.NewOrm()
  85. _, err := db.Raw("update t_substation_area set voltage_level=? where id=?", voltagelavel, id).Exec()
  86. return err
  87. }
  88. //获取指定scd的间隔信息
  89. func (c *ScdAreaMgr) GetAreaList(scdid int64) ([]orm.Params, error) {
  90. db := orm.NewOrm()
  91. sql := "select t.*,(select count(1) from t_area_ied_relation where area_id=t.id) iedcount from t_substation_area t where t.scd_id=? order by t.name"
  92. rowset := []orm.Params{}
  93. _, err := db.Raw(sql, scdid).Values(&rowset)
  94. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid})
  95. if err != nil {
  96. logger.Logger.Error(err, sqllog)
  97. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  98. } else {
  99. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  100. }
  101. return rowset, nil
  102. }
  103. //获取指定scd和电压等级的间隔信息
  104. func (c *ScdAreaMgr) GetAreaListByVol(scdid int64, vl int32) ([]orm.Params, error) {
  105. db := orm.NewOrm()
  106. sql := "select * from t_substation_area where scd_id=? and voltage_level=? order by name"
  107. rowset := []orm.Params{}
  108. _, err := db.Raw(sql, scdid, vl).Values(&rowset)
  109. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid, vl})
  110. if err != nil {
  111. logger.Logger.Error(err, sqllog)
  112. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  113. } else {
  114. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  115. }
  116. return rowset, nil
  117. }
  118. //获取指定间隔下的IED列表
  119. func (c *ScdAreaMgr) GetIedList(scdid int64, voltage_level_id, areaid int32, device_type string) ([]orm.Params, error) {
  120. db := orm.NewOrm()
  121. sql := "select * from t_substation_area t,t_area_ied_relation t1 where t.scd_id=? and t.id=t1.area_id "
  122. sqlParamters := []interface{}{}
  123. sqlParamters = append(sqlParamters, scdid)
  124. if voltage_level_id > 0 {
  125. sql = sql + " and t.voltage_level=?"
  126. sqlParamters = append(sqlParamters, voltage_level_id)
  127. }
  128. if areaid > 0 {
  129. sql = sql + " and t1.area_id=?"
  130. sqlParamters = append(sqlParamters, areaid)
  131. }
  132. scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
  133. if serr != nil {
  134. return nil, serr
  135. }
  136. if scdXmlObj == nil {
  137. return nil, errors.New("无效的SCD")
  138. }
  139. rowset := []orm.Params{}
  140. if device_type != "" {
  141. //根据装备类型查询IED
  142. sql = sql + " and t1.ied_type=?"
  143. sqlParamters = append(sqlParamters, device_type)
  144. }
  145. _, err := db.Raw(sql, sqlParamters).Values(&rowset)
  146. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
  147. if err != nil {
  148. logger.Logger.Error(err, sqllog)
  149. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  150. } else {
  151. scdNode := new(ScdNode)
  152. for _, row := range rowset {
  153. iedid, _ := strconv.ParseInt(tools.IsEmpty(row["ied_id"]), 10, 64)
  154. iedObj := scdNode.GetIedByID(scdXmlObj, tools.IsEmpty(scdid), iedid)
  155. if iedObj == nil {
  156. continue
  157. }
  158. row["attr_name"] = iedObj.Name
  159. row["attr_desc"] = iedObj.Desc
  160. row["attr_config_version"] = iedObj.ConfigVersion
  161. row["attr_type"] = iedObj.Type
  162. row["attr_manufacturer"] = iedObj.Manufacturer
  163. row["ied_id"] = iedObj.NodeId
  164. }
  165. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  166. }
  167. return rowset, nil
  168. }
  169. //获取指定SCD的IED类型列表
  170. func (c *ScdAreaMgr) GetIedTypeList(scdid int64) ([]orm.Params, error) {
  171. db := orm.NewOrm()
  172. sql := "select t2.* from t_area_ied_relation t1,global_const_code t2 where t1.scd_id=? and t1.ied_type=t2.code and t2.parentcode='device_type' group by t1.ied_type "
  173. sqlParamters := []interface{}{}
  174. rowset := []orm.Params{}
  175. sqlParamters = append(sqlParamters, scdid)
  176. _, err := db.Raw(sql, sqlParamters).Values(&rowset)
  177. sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
  178. if err != nil {
  179. logger.Logger.Error(err, sqllog)
  180. new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
  181. }
  182. return rowset, nil
  183. }
  184. func (c *ScdAreaMgr) One(id string) (interface{}, error) {
  185. db := orm.NewOrm()
  186. idInt, err := strconv.ParseInt(id, 10, 64)
  187. if err != nil {
  188. return nil, err
  189. }
  190. areaM := T_substation_area{Id: idInt}
  191. err = db.Read(&areaM)
  192. if err == nil {
  193. return areaM, nil
  194. }
  195. return nil, err
  196. }
  197. //重置scd的间隔信息
  198. func (c *ScdAreaMgr) Reset(scdid int64) error {
  199. db := orm.NewOrm()
  200. db.Raw("delete from t_area_ied_relation where area_id in(select id from t_substation_area where scd_id=?)", scdid).Exec()
  201. db.Raw("delete from t_substation_area where scd_id=?", scdid).Exec()
  202. sql := "select * from t_scd_ied_attrs where scd_id=?"
  203. rowset := []orm.Params{}
  204. _, err := db.Raw(sql, scdid).Values(&rowset)
  205. if err != nil {
  206. log.Println(err)
  207. return err
  208. }
  209. for _, row := range rowset {
  210. ied := new(t_scd_node_scl)
  211. ied.Id, _ = strconv.ParseInt(tools.IsEmpty(row["node_id"]), 10, 64)
  212. iedNodeDesc := tools.IsEmpty(row["attr_desc"])
  213. ied.NodeName = tools.IsEmpty(row["attr_name"])
  214. ied.ScdId = scdid
  215. c.AppendIedNode(scdid, ied.Id, ied.NodeName, iedNodeDesc)
  216. }
  217. logdesc := fmt.Sprintf("重置SCD %d间隔成功", scdid)
  218. new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Update, enum.OptEventType_Bus, enum.OptEventLevel_Low, logdesc, c.GetUserInfo())
  219. return nil
  220. }
  221. //根据scd中的Bay节点解析间隔
  222. func (c *ScdAreaMgr) ParseBay(substation_id int, lst []*node_attr.NVoltage) {
  223. if c.DeviceTypeDef == nil {
  224. c.Init(c.ScdId)
  225. }
  226. db := orm.NewOrm()
  227. voltages := []string{"其它", "其他"}
  228. for _, item := range lst {
  229. voltages = append(voltages, item.Name)
  230. }
  231. //电压等级节点属性表:t_scd_voltage_attrs。对比电压等级与定义的码表,如果缺失时自动新增
  232. sql := `select t1.id,t1.name from global_const_code t1 where t1.parentcode='voltage_level' and t1.name in('` + strings.Join(voltages, "','") + `') `
  233. rowset := []orm.Params{}
  234. _, err := db.Raw(sql).Values(&rowset)
  235. if err != nil {
  236. logger.Logger.Error(err, fmt.Sprintf("SQL:%s ", sql))
  237. } else {
  238. voltage_id_map := map[string]string{}
  239. for _, row := range rowset {
  240. voltage_name := tools.IsEmpty(row["name"])
  241. voltage_id_map[voltage_name] = tools.IsEmpty(row["id"])
  242. }
  243. clearSql := "delete from t_substation_area where substation_id=? and scd_id=?"
  244. _, err = db.Raw(clearSql, substation_id, c.ScdId).Exec()
  245. if err != nil {
  246. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{substation_id, c.ScdId}))
  247. return
  248. }
  249. //先清除ied与间隔关联关系
  250. clearSql = "delete from t_area_ied_relation where area_id in(select id from t_substation_area where substation_id=? and scd_id=?)"
  251. _, err = db.Raw(clearSql, substation_id, c.ScdId).Exec()
  252. if err != nil {
  253. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{substation_id, c.ScdId}))
  254. return
  255. }
  256. bayCols := "insert into t_substation_area(substation_id,scd_id,voltage_level,name,name_no)values"
  257. bayValues := []string{}
  258. for _, volitem := range lst {
  259. voltage_name := volitem.Name
  260. voltage_id := voltage_id_map[voltage_name]
  261. if voltage_id == "" {
  262. voltage_id = voltage_id_map["其它"]
  263. }
  264. if voltage_id == "" {
  265. voltage_id = voltage_id_map["其他"]
  266. }
  267. for _, bayitem := range volitem.Bay {
  268. bayValues = append(bayValues, fmt.Sprintf(`(%d,%d,%s,'%s','')`, substation_id, c.ScdId, voltage_id, bayitem.Name))
  269. }
  270. sql := bayCols + strings.Join(bayValues, ",")
  271. //添加间隔
  272. _, err = db.Raw(sql).Exec()
  273. if err != nil {
  274. logger.Logger.Error(err, fmt.Sprintf("SQL:%s", sql))
  275. } else {
  276. //创建ied与间隔关联关系
  277. relCols := "insert into t_area_ied_relation(scd_id, area_id,ied_id,ied_name,ied_type)values"
  278. relValues := []string{}
  279. for _, bayitem := range volitem.Bay {
  280. relValues = []string{}
  281. areaRowset := []orm.Params{}
  282. _, err = db.Raw("select id from t_substation_area where substation_id=? and scd_id=? and voltage_level=?", substation_id, c.ScdId, voltage_id).Values(&areaRowset)
  283. if err != nil {
  284. logger.Logger.Error(err)
  285. } else {
  286. areaid := tools.IsEmpty(areaRowset[0]["id"])
  287. for _, iedItem := range bayitem.IED {
  288. //解析类型
  289. iedtype := "xy" //其他装置类型
  290. name := iedItem.Name
  291. if len(name) >= 3 {
  292. lastchar := name[0:2]
  293. if c.DeviceTypeDef[lastchar] == 0 {
  294. lastchar = name[0:1]
  295. if c.DeviceTypeDef[lastchar] == 0 {
  296. iedtype = "xy"
  297. } else {
  298. iedtype = lastchar
  299. }
  300. } else {
  301. iedtype = lastchar
  302. }
  303. }
  304. relValues = append(relValues, fmt.Sprintf("(%d,%s,%d,%s,%s)", c.ScdId, areaid, iedItem.NodeId, iedItem.Name, iedtype))
  305. }
  306. if len(relValues) == 0 {
  307. continue
  308. }
  309. sql2 := relCols + strings.Join(relValues, ",")
  310. //添加间隔
  311. _, err = db.Raw(sql2).Exec()
  312. if err != nil {
  313. logger.Logger.Error(err, fmt.Sprintf("SQL:%s", sql2))
  314. }
  315. }
  316. }
  317. }
  318. }
  319. }
  320. }
  321. //添加新的需要解析的Ied装置
  322. //name:ied的name属性值
  323. //str:ied的desc属性值
  324. func (c *ScdAreaMgr) AppendIedNode(scdId, iedId int64, name, str string) {
  325. //fmt.Println("ScdAreaMgr.AppendIedNode:" + name + " " + str)
  326. if str == "" {
  327. return
  328. }
  329. if c.DeviceTypeDef == nil {
  330. c.Init(c.ScdId)
  331. }
  332. go func(scdId, iedId int64, name, str string) {
  333. areaStartPos := 0
  334. areaEndPos := 0
  335. reg := regexp.MustCompile(`(?i)kv`)
  336. r := reg.FindStringIndex(str)
  337. if r != nil {
  338. areaStartPos = r[1]
  339. }
  340. voltagelevel := strings.ToLower(strings.Trim(str[0:areaStartPos], " "))
  341. //优先匹配关键词
  342. reg = regexp.MustCompile(`(测控|智能|保护|合并)`)
  343. r = reg.FindStringIndex(str)
  344. if r != nil {
  345. areaEndPos = r[0]
  346. }
  347. areaResult := ""
  348. if len(r) == 0 {
  349. //次级匹配关键词。在装置desc中未发现任意优先匹配关键词,再按以下关键尝试匹配
  350. reg = regexp.MustCompile(`(分段|备|自投)`)
  351. r = reg.FindStringIndex(str)
  352. if r != nil {
  353. areaEndPos = r[0]
  354. }
  355. if areaEndPos == 0 {
  356. areaResult = "公用"
  357. } else {
  358. areaResult = strings.Trim(str[areaStartPos:areaEndPos], " ")
  359. }
  360. } else {
  361. areaResult = strings.Trim(str[areaStartPos:areaEndPos], " ")
  362. }
  363. if len(areaResult) < 2 {
  364. areaResult = str
  365. }
  366. areaResult = strings.Trim(strings.ReplaceAll(areaResult, "线路", "线"), " ")
  367. //logger.Logger.Debug(fmt.Sprintf("解析装置%s电压及间隔:电压%s 间隔:%s", str, voltagelevel, areaResult))
  368. c.CacheLock.Lock()
  369. //解析类型
  370. iedtype := "xy" //其他装置类型
  371. if len(name) >= 3 {
  372. lastchar := name[0:2]
  373. if c.DeviceTypeDef[lastchar] == 0 {
  374. lastchar = name[0:1]
  375. if c.DeviceTypeDef[lastchar] == 0 {
  376. iedtype = "xy"
  377. } else {
  378. iedtype = lastchar
  379. }
  380. } else {
  381. iedtype = lastchar
  382. }
  383. }
  384. //所属间隔判断规则
  385. //1、判断解析得到的间隔名称是否已存在
  386. //2、不存在时,根据装置name中的数字编号(如CM1101中的1101),查找同编号且已归属间隔的任意设置所属间隔
  387. db := orm.NewOrm()
  388. voltagelevelid := c.VoltageLevelDef[voltagelevel]
  389. logger.Logger.Debug(fmt.Sprintf("%s %s 电压等级:%s ID:%d 间隔名称:%s ", name, str, voltagelevel, voltagelevelid, areaResult))
  390. nameNo := ""
  391. hasfirst := false
  392. for _, char := range name {
  393. if char >= '0' && char <= '9' {
  394. nameNo = nameNo + string(char)
  395. if !hasfirst {
  396. hasfirst = true
  397. }
  398. if len(nameNo) == 3 {
  399. //最多取3位数字
  400. break
  401. }
  402. continue
  403. }
  404. if hasfirst {
  405. break
  406. }
  407. }
  408. if voltagelevelid == 0 && len(nameNo) > 1 {
  409. //尝试使用从name中解析的电压等级值是否正确
  410. voltagelevelid = c.VoltageLevelDef[nameNo+"kv"]
  411. //如果电压等级无效,尝试使用前2位做为电压等级
  412. if voltagelevelid == 0 && len(nameNo) == 3 {
  413. nameNo = nameNo[0:2]
  414. voltagelevelid = c.VoltageLevelDef[nameNo+"kv"]
  415. }
  416. }
  417. isNoOtherVL := 1
  418. if voltagelevelid == 0 {
  419. voltagelevelid = c.VoltageLevelDef[nameNo+"kv"]
  420. if voltagelevelid == 0 {
  421. isNoOtherVL = 0
  422. voltagelevelid = c.VoltageLevelDef["其它"]
  423. }
  424. }
  425. if otherIedNameList[name] {
  426. voltagelevelid = c.VoltageLevelDef["其它"]
  427. }
  428. areaid := c.CacheAreaID[fmt.Sprintf("%d%s", voltagelevelid, areaResult)]
  429. if areaid == 0 {
  430. //新增一个新的间隔
  431. areaM := T_substation_area{}
  432. areaM.Name = areaResult
  433. areaM.ScdId = scdId
  434. areaM.NameNo = nameNo
  435. areaM.VoltageLevel = voltagelevelid
  436. areaM.CreatedTime = tools.NowTime()
  437. newid, err := db.Insert(&areaM)
  438. if err != nil {
  439. logger.Logger.Error(err)
  440. }
  441. c.CacheAreaID[fmt.Sprintf("%d%s", voltagelevelid, areaResult)] = int32(newid)
  442. areaid = int32(newid)
  443. } else {
  444. //如果当前电压等级不是“其它”,则将之前归属于其他电压的间隔更新到当前电压等级下
  445. if isNoOtherVL == 1 {
  446. db.Raw("update t_substation_area set voltage_level=? where name_no=? and scd_id=?", voltagelevelid, nameNo, scdId).Exec()
  447. }
  448. }
  449. c.CacheLock.Unlock()
  450. rel := t_area_ied_relation{AreaId: areaid, IedId: iedId, IedName: name, IedType: iedtype, ScdId: scdId}
  451. db.Insert(&rel)
  452. //logdesc := fmt.Sprintf("添加间隔,操作数据:%+v", rel)
  453. //new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Low, logdesc, c.UserInfo)
  454. }(scdId, iedId, name, str)
  455. }
  456. //测试
  457. func (c *ScdAreaMgr) TestAppendNode(iedname string) {
  458. //t := t_scd_node_scl{NodeName: iedname}
  459. //c.AppendIedNode(&t)
  460. }