checktools_area.go 16 KB

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