123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- package bo
- import (
- "errors"
- "fmt"
- "log"
- "regexp"
- "scd_check_tools/logger"
- "scd_check_tools/models/enum"
- "scd_check_tools/models/node_attr"
- "scd_check_tools/tools"
- "strconv"
- "strings"
- "sync"
- "github.com/astaxie/beego/orm"
- )
- //SCD间隔管理
- type ScdAreaMgr struct {
- DeviceBaseModel
- //SCD文件ID
- ScdId int64
- //电压等级定义
- VoltageLevelDef map[string]int32
- //设备类型定义
- DeviceTypeDef map[string]int
- CacheAreaID map[string]int32
- CacheAreaIDByIedNameNo map[string]int32
- CacheLock sync.RWMutex
- }
- type T_substation_area struct {
- Id int64 `orm:"pk"`
- Name string
- NameNo string
- ScdId int64
- VoltageLevel int32
- DispatchNo string
- SubstationId int
- CreatedBy int
- CreatedTime string
- }
- type t_area_ied_relation struct {
- Id int32 `orm:"pk"`
- AreaId int32
- IedId int64
- IedName string
- IedType string
- IedDesc string
- PType string //归属设备类型
- Vol string //电压编码
- PCode string //归属设备编码
- IedNo string //IED编号(A\B\C)
- ScdId int64
- }
- // 其他非标准装置列表。通过系统参数OtherIedNameList维护
- var otherIedNameList map[string]bool
- func init() {
- orm.RegisterModel(new(T_substation_area))
- orm.RegisterModel(new(t_area_ied_relation))
- }
- func (c *ScdAreaMgr) Init(scdid int64) {
- c.VoltageLevelDef = map[string]int32{}
- c.DeviceTypeDef = map[string]int{}
- c.CacheAreaIDByIedNameNo = map[string]int32{}
- c.CacheAreaID = map[string]int32{}
- c.CacheLock = sync.RWMutex{}
- db := orm.NewOrm()
- rowset := []orm.Params{}
- db.Raw("select * from global_const_code where parentcode=?", "voltage_level").Values(&rowset)
- for _, row := range rowset {
- vl := strings.ToLower(tools.IsEmpty(row["code"]))
- id, _ := strconv.ParseInt(tools.IsEmpty(row["id"]), 10, 32)
- c.VoltageLevelDef[strings.ReplaceAll(vl, "v_level_", "")] = int32(id)
- }
- db.Raw("select * from global_const_code where parentcode=?", "device_type").Values(&rowset)
- for _, row := range rowset {
- vl := tools.IsEmpty(row["code"])
- c.DeviceTypeDef[vl] = 1
- }
- v, _ := GetSysParamValue("OtherIedNameList", "")
- otherIedNameList = map[string]bool{}
- if v != "" {
- vs := strings.Split(v, ",")
- for _, vv := range vs {
- otherIedNameList[vv] = true
- }
- }
- }
- //保存指定间隔所属的电压等级
- func (c *ScdAreaMgr) SetVoltageLevel(id string, voltagelevel int) error {
- db := orm.NewOrm()
- _, err := db.Raw("update t_substation_area set voltage_level=? where id=?", voltagelevel, id).Exec()
- return err
- }
- //修改指定间隔的名称
- func (c *ScdAreaMgr) UpdateName(scdid int64, area_id int, name string) error {
- db := orm.NewOrm()
- areaM := T_substation_area{Id: int64(area_id), ScdId: scdid}
- err := db.Read(&areaM)
- if err != nil {
- logger.Logger.Error(err)
- return err
- }
- areaM.Name = name
- _, err = db.Update(&areaM)
- if err != nil {
- logger.Logger.Error(err)
- }
- return err
- }
- //修改指定IED的所属间隔
- func (c *ScdAreaMgr) UpdateIedArea(scdid int64, iedname string, area_id int) error {
- db := orm.NewOrm()
- _, err := db.Raw("update t_area_ied_relation set area_id=? where scd_id=? and ied_name=?", area_id, scdid, iedname).Exec()
- return err
- }
- //获取指定scd的间隔信息
- func (c *ScdAreaMgr) GetAreaList(scdid int64) ([]orm.Params, error) {
- db := orm.NewOrm()
- 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"
- rowset := []orm.Params{}
- _, err := db.Raw(sql, scdid).Values(&rowset)
- sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid})
- if err != nil {
- logger.Logger.Error(err, sqllog)
- new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- } else {
- new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- }
- return rowset, nil
- }
- //获取指定scd和电压等级的间隔信息
- func (c *ScdAreaMgr) GetAreaListByVol(scdid int64, vl int32) ([]orm.Params, error) {
- db := orm.NewOrm()
- sql := "select * from t_substation_area where scd_id=? and voltage_level=? order by name"
- rowset := []orm.Params{}
- _, err := db.Raw(sql, scdid, vl).Values(&rowset)
- sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{scdid, vl})
- if err != nil {
- logger.Logger.Error(err, sqllog)
- new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- } else {
- new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- }
- return rowset, nil
- }
- //获取指定间隔下的IED列表
- func (c *ScdAreaMgr) GetIedList(scdid int64, voltage_level_id, areaid int32, device_type string) ([]orm.Params, error) {
- db := orm.NewOrm()
- sql := "select * from t_substation_area t,t_area_ied_relation t1 where t.scd_id=? and t.id=t1.area_id "
- sqlParamters := []interface{}{}
- sqlParamters = append(sqlParamters, scdid)
- if voltage_level_id > 0 {
- sql = sql + " and t.voltage_level=?"
- sqlParamters = append(sqlParamters, voltage_level_id)
- }
- if areaid > 0 {
- sql = sql + " and t1.area_id=?"
- sqlParamters = append(sqlParamters, areaid)
- }
- scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid))
- if serr != nil {
- return nil, serr
- }
- if scdXmlObj == nil {
- return nil, errors.New("无效的SCD")
- }
- rowset := []orm.Params{}
- if device_type != "" {
- //根据装备类型查询IED
- sql = sql + " and t1.ied_type=?"
- sqlParamters = append(sqlParamters, device_type)
- }
- _, err := db.Raw(sql, sqlParamters).Values(&rowset)
- sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
- if err != nil {
- logger.Logger.Error(err, sqllog)
- new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- } else {
- scdNode := new(ScdNode)
- for _, row := range rowset {
- iedid, _ := strconv.ParseInt(tools.IsEmpty(row["ied_id"]), 10, 64)
- iedObj := scdNode.GetIedByID(scdXmlObj, tools.IsEmpty(scdid), iedid)
- if iedObj == nil {
- continue
- }
- row["attr_name"] = iedObj.Name
- row["attr_desc"] = iedObj.Desc
- row["attr_config_version"] = iedObj.ConfigVersion
- row["attr_type"] = iedObj.Type
- row["attr_manufacturer"] = iedObj.Manufacturer
- row["ied_id"] = iedObj.NodeId
- }
- new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- }
- return rowset, nil
- }
- //获取指定SCD的IED类型列表
- func (c *ScdAreaMgr) GetIedTypeList(scdid int64) ([]orm.Params, error) {
- db := orm.NewOrm()
- 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 "
- sqlParamters := []interface{}{}
- rowset := []orm.Params{}
- sqlParamters = append(sqlParamters, scdid)
- _, err := db.Raw(sql, sqlParamters).Values(&rowset)
- sqllog := fmt.Sprintf("SQL:%s 参数:%+v", sql, sqlParamters)
- if err != nil {
- logger.Logger.Error(err, sqllog)
- new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo())
- }
- return rowset, nil
- }
- func (c *ScdAreaMgr) One(id string) (interface{}, error) {
- db := orm.NewOrm()
- idInt, err := strconv.ParseInt(id, 10, 64)
- if err != nil {
- return nil, err
- }
- areaM := T_substation_area{Id: idInt}
- err = db.Read(&areaM)
- if err == nil {
- return areaM, nil
- }
- return nil, err
- }
- //重置scd的间隔信息
- func (c *ScdAreaMgr) Reset(scdid int64) error {
- db := orm.NewOrm()
- db.Raw("delete from t_area_ied_relation where area_id in(select id from t_substation_area where scd_id=?)", scdid).Exec()
- db.Raw("delete from t_substation_area where scd_id=?", scdid).Exec()
- sql := "select * from t_scd_ied_attrs where scd_id=?"
- rowset := []orm.Params{}
- _, err := db.Raw(sql, scdid).Values(&rowset)
- if err != nil {
- log.Println(err)
- return err
- }
- for _, row := range rowset {
- ied := new(t_scd_node_scl)
- ied.Id, _ = strconv.ParseInt(tools.IsEmpty(row["node_id"]), 10, 64)
- iedNodeDesc := tools.IsEmpty(row["attr_desc"])
- ied.NodeName = tools.IsEmpty(row["attr_name"])
- ied.ScdId = scdid
- c.AppendIedNode(scdid, ied.Id, ied.NodeName, iedNodeDesc)
- }
- logdesc := fmt.Sprintf("重置SCD %d间隔成功", scdid)
- new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Update, enum.OptEventType_Bus, enum.OptEventLevel_Low, logdesc, c.GetUserInfo())
- return nil
- }
- //根据scd中的Bay节点解析间隔
- func (c *ScdAreaMgr) ParseBay(substation_id int, lst []*node_attr.NVoltage) {
- if c.DeviceTypeDef == nil {
- c.Init(c.ScdId)
- }
- db := orm.NewOrm()
- voltages := []string{"其它", "其他"}
- for _, item := range lst {
- voltages = append(voltages, item.Name)
- }
- //电压等级节点属性表:t_scd_voltage_attrs。对比电压等级与定义的码表,如果缺失时自动新增
- 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, "','") + `') `
- rowset := []orm.Params{}
- _, err := db.Raw(sql).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s ", sql))
- } else {
- voltage_id_map := map[string]string{}
- for _, row := range rowset {
- voltage_name := tools.IsEmpty(row["code"])
- voltage_id_map[strings.ReplaceAll(voltage_name, "v_level_", "")] = tools.IsEmpty(row["id"])
- }
- clearSql := "delete from t_substation_area where substation_id=? and scd_id=?"
- _, err = db.Raw(clearSql, substation_id, c.ScdId).Exec()
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{substation_id, c.ScdId}))
- return
- }
- //先清除ied与间隔关联关系
- clearSql = "delete from t_area_ied_relation where area_id in(select id from t_substation_area where substation_id=? and scd_id=?)"
- _, err = db.Raw(clearSql, substation_id, c.ScdId).Exec()
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", clearSql, []interface{}{substation_id, c.ScdId}))
- return
- }
- bayCols := "insert into t_substation_area(substation_id,scd_id,voltage_level,name,name_no)values"
- bayValues := []string{}
- for _, volitem := range lst {
- voltage_name := volitem.Name
- voltage_id := voltage_id_map[voltage_name]
- if voltage_id == "" {
- voltage_id = voltage_id_map["其它"]
- }
- if voltage_id == "" {
- voltage_id = voltage_id_map["其他"]
- }
- for _, bayitem := range volitem.Bay {
- bayValues = append(bayValues, fmt.Sprintf(`(%d,%d,%s,'%s','')`, substation_id, c.ScdId, voltage_id, bayitem.Name))
- }
- sql := bayCols + strings.Join(bayValues, ",")
- //添加间隔
- _, err = db.Raw(sql).Exec()
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s", sql))
- } else {
- //创建ied与间隔关联关系
- relCols := "insert into t_area_ied_relation(scd_id, area_id,ied_id,ied_name,ied_desc,ied_type,p_type,vol,p_code,ied_no)values"
- relValues := []string{}
- for _, bayitem := range volitem.Bay {
- relValues = []string{}
- areaRowset := []orm.Params{}
- _, 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)
- if err != nil {
- logger.Logger.Error(err)
- } else {
- areaid := tools.IsEmpty(areaRowset[0]["id"])
- for _, iedItem := range bayitem.IED {
- //解析类型
- //补全实际ied name为8位
- new_ied_name_full := new(ScdParse).ParseIedName(iedItem.Name)
- iedtype := "xy" //其他装置类型
- ptype := ""
- vol := ""
- pcode := ""
- iedno := ""
- name := iedItem.Name
- if len(name) >= 3 {
- lastchar := new_ied_name_full[0] + new_ied_name_full[1]
- ptype = new_ied_name_full[2]
- vol = new_ied_name_full[3] + new_ied_name_full[4]
- pcode = new_ied_name_full[5] + new_ied_name_full[6]
- iedno = new_ied_name_full[7]
- if c.DeviceTypeDef[lastchar] == 0 {
- iedtype = "xy"
- } else {
- iedtype = lastchar
- }
- voltagelevelid := c.VoltageLevelDef[vol]
- if voltagelevelid == 0 {
- vol = "999"
- }
- }
- relValues = append(relValues, fmt.Sprintf("(%d,%s,%d,'%s','%s','%s','%s','%s','%s','%s')", c.ScdId, areaid, iedItem.NodeId, iedItem.Name, iedItem.Desc, iedtype, ptype, vol, pcode, iedno))
- }
- if len(relValues) == 0 {
- continue
- }
- sql2 := relCols + strings.Join(relValues, ",")
- //添加间隔
- _, err = db.Raw(sql2).Exec()
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s", sql2))
- }
- }
- }
- }
- }
- }
- }
- //添加新的需要解析的Ied装置
- //name:ied的name属性值
- //str:ied的desc属性值
- func (c *ScdAreaMgr) AppendIedNode(scdId, iedId int64, name, str string) {
- //fmt.Println("ScdAreaMgr.AppendIedNode:" + name + " " + str)
- if str == "" {
- return
- }
- if c.DeviceTypeDef == nil {
- c.Init(c.ScdId)
- }
- go func(scdId, iedId int64, name, str string) {
- areaStartPos := 0
- areaEndPos := 0
- reg := regexp.MustCompile(`(?i)kv`)
- r := reg.FindStringIndex(str)
- if r != nil {
- areaStartPos = r[1]
- }
- voltagelevel := strings.ToLower(strings.Trim(str[0:areaStartPos], " "))
- //优先匹配关键词
- reg = regexp.MustCompile(`(测控|智能|保护|合并)`)
- r = reg.FindStringIndex(str)
- if r != nil {
- areaEndPos = r[0]
- }
- areaResult := ""
- if len(r) == 0 {
- //次级匹配关键词。在装置desc中未发现任意优先匹配关键词,再按以下关键尝试匹配
- reg = regexp.MustCompile(`(分段|备|自投)`)
- r = reg.FindStringIndex(str)
- if r != nil {
- areaEndPos = r[0]
- }
- if areaEndPos == 0 {
- areaResult = "公用"
- } else {
- areaResult = strings.Trim(str[areaStartPos:areaEndPos], " ")
- }
- } else {
- areaResult = strings.Trim(str[areaStartPos:areaEndPos], " ")
- }
- if len(areaResult) < 2 {
- areaResult = str
- }
- areaResult = strings.Trim(strings.ReplaceAll(areaResult, "线路", "线"), " ")
- //logger.Logger.Debug(fmt.Sprintf("解析装置%s电压及间隔:电压%s 间隔:%s", str, voltagelevel, areaResult))
- c.CacheLock.Lock()
- //补全实际ied name为8位
- new_ied_name_full := new(ScdParse).ParseIedName(name)
- //解析类型
- iedtype := "xy" //其他装置类型
- ptype := ""
- vol := ""
- pcode := ""
- iedno := ""
- if len(name) >= 3 {
- lastchar := new_ied_name_full[0] + new_ied_name_full[1]
- if c.DeviceTypeDef[lastchar] == 0 {
- iedtype = "xy"
- } else {
- iedtype = lastchar
- }
- ptype = new_ied_name_full[2]
- vol = new_ied_name_full[3] + new_ied_name_full[4]
- pcode = new_ied_name_full[5] + new_ied_name_full[6]
- iedno = new_ied_name_full[7]
- voltagelevel = vol
- }
- //所属间隔判断规则
- //1、判断解析得到的间隔名称是否已存在
- //2、不存在时,根据装置name中的数字编号(如CM1101中的1101),查找同编号且已归属间隔的任意设置所属间隔
- db := orm.NewOrm()
- voltagelevelid := c.VoltageLevelDef[voltagelevel]
- logger.Logger.Debug(fmt.Sprintf("%s %s 电压等级:%s ID:%d 间隔名称:%s ", name, str, voltagelevel, voltagelevelid, areaResult))
- isNoOtherVL := 1
- if voltagelevelid == 0 {
- isNoOtherVL = 0
- voltagelevelid = c.VoltageLevelDef["其它"]
- vol = "999"
- }
- if otherIedNameList[name] {
- voltagelevelid = c.VoltageLevelDef["其它"]
- }
- areaid := c.CacheAreaID[fmt.Sprintf("%d%s", voltagelevelid, areaResult)]
- if areaid == 0 {
- //新增一个新的间隔
- areaM := T_substation_area{}
- areaM.Name = areaResult
- areaM.ScdId = scdId
- areaM.NameNo = vol
- areaM.VoltageLevel = voltagelevelid
- areaM.CreatedTime = tools.NowTime()
- newid, err := db.Insert(&areaM)
- if err != nil {
- logger.Logger.Error(err)
- }
- c.CacheAreaID[fmt.Sprintf("%d%s", voltagelevelid, areaResult)] = int32(newid)
- areaid = int32(newid)
- } else {
- //如果当前电压等级不是“其它”,则将之前归属于其他电压的间隔更新到当前电压等级下
- if isNoOtherVL == 1 {
- db.Raw("update t_substation_area set voltage_level=? where name_no=? and scd_id=?", voltagelevelid, vol, scdId).Exec()
- }
- }
- c.CacheLock.Unlock()
- rel := t_area_ied_relation{AreaId: areaid, IedId: iedId, IedName: name, IedDesc: str, IedType: iedtype, PType: ptype, Vol: vol, PCode: pcode, IedNo: iedno, ScdId: scdId}
- db.Insert(&rel)
- //logdesc := fmt.Sprintf("添加间隔,操作数据:%+v", rel)
- //new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Low, logdesc, c.UserInfo)
- }(scdId, iedId, name, str)
- }
- //测试
- func (c *ScdAreaMgr) TestAppendNode(iedname string) {
- //t := t_scd_node_scl{NodeName: iedname}
- //c.AppendIedNode(&t)
- }
|