scd_area.go 16 KB

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