485 lines
14 KiB
Go
485 lines
14 KiB
Go
|
package repo
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"joylink.club/rtsssimulation/repo/dto"
|
||
|
"joylink.club/rtsssimulation/repo/model"
|
||
|
)
|
||
|
|
||
|
// 城轨uid
|
||
|
type CgUid struct {
|
||
|
// 城市
|
||
|
city string
|
||
|
// 线路
|
||
|
line string
|
||
|
// 设备编号
|
||
|
codes []string
|
||
|
// codestr
|
||
|
codestr string
|
||
|
// uid
|
||
|
idstr string
|
||
|
}
|
||
|
|
||
|
func NewCgUid(city string, line string, codes ...string) *CgUid {
|
||
|
if city == "" || line == "" {
|
||
|
panic(fmt.Errorf("创建城轨uid错误: 城市、线路、车站不能为空 city=%s, line=%s", city, line))
|
||
|
}
|
||
|
l := len(codes)
|
||
|
if l == 0 {
|
||
|
panic(fmt.Errorf("创建城轨uid错误: codes不能为空"))
|
||
|
}
|
||
|
codestr := strings.Join(codes, "_")
|
||
|
elems := []string{city, line, codestr}
|
||
|
uid := strings.Join(elems, "_")
|
||
|
return &CgUid{
|
||
|
city: city,
|
||
|
line: line,
|
||
|
codes: codes,
|
||
|
codestr: codestr,
|
||
|
idstr: uid,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (u *CgUid) Id() string {
|
||
|
return u.idstr
|
||
|
}
|
||
|
|
||
|
func (u *CgUid) Code() string {
|
||
|
return u.codestr
|
||
|
}
|
||
|
|
||
|
type idMap struct {
|
||
|
// 数据id
|
||
|
Did string
|
||
|
// 元素id
|
||
|
Eid uint32
|
||
|
// 唯一id
|
||
|
Uid model.Uid
|
||
|
}
|
||
|
|
||
|
func NewIdMap(did string, eid uint32, uid model.Uid) *idMap {
|
||
|
return &idMap{
|
||
|
Did: did,
|
||
|
Eid: eid,
|
||
|
Uid: uid,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m *idMap) DeId() string {
|
||
|
return DeID(m.Did, m.Eid)
|
||
|
}
|
||
|
func (m *idMap) Debug() string {
|
||
|
return fmt.Sprintf("{数据id=%s, 元素id=%v, uid=%s}", m.Did, m.Eid, m.Uid.Id())
|
||
|
}
|
||
|
|
||
|
// 数据元素id key生成
|
||
|
// did - 数据id
|
||
|
// eid - 元素id
|
||
|
func DeID(did string, eid uint32) string {
|
||
|
return fmt.Sprintf("%s_%v", did, eid)
|
||
|
}
|
||
|
|
||
|
// id映射表
|
||
|
type IdMapping struct {
|
||
|
// 数据元素id映射
|
||
|
deidMap map[string]*idMap
|
||
|
// uid映射(只存储最初的idMap,实际中一个uid可能对应多个数据元素id)
|
||
|
uidMap map[string]*idMap
|
||
|
}
|
||
|
|
||
|
func (m *IdMapping) queryByDeId(deid string) *idMap {
|
||
|
return m.deidMap[deid]
|
||
|
}
|
||
|
|
||
|
func (m *IdMapping) queryByDidAndEid(did string, eid uint32) *idMap {
|
||
|
id := DeID(did, eid)
|
||
|
return m.deidMap[id]
|
||
|
}
|
||
|
|
||
|
func (m *IdMapping) add(idmap *idMap) {
|
||
|
if idmap == nil {
|
||
|
panic(fmt.Errorf("添加id映射表错误: idmap不能为空"))
|
||
|
}
|
||
|
m.deidMap[idmap.DeId()] = idmap
|
||
|
}
|
||
|
|
||
|
func (m *IdMapping) checkUidAndAdd(idmap *idMap) (existed *idMap, uidExisted bool) {
|
||
|
if idmap == nil {
|
||
|
panic(fmt.Errorf("添加id映射表错误: idmap不能为空"))
|
||
|
}
|
||
|
m.deidMap[idmap.DeId()] = idmap
|
||
|
existed, ok := m.uidMap[idmap.Uid.Id()]
|
||
|
if ok {
|
||
|
uidExisted = true
|
||
|
} else {
|
||
|
m.uidMap[idmap.Uid.Id()] = idmap
|
||
|
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 构建id映射
|
||
|
func BuildIdMapping(msgs *dto.Repo, errRecord *ErrorRecord) *IdMapping {
|
||
|
if cg := msgs.GetCgData(); cg != nil {
|
||
|
return BuildCgIdMapping(cg, errRecord)
|
||
|
} else if gt := msgs.GetGtData(); gt != nil {
|
||
|
return BuildGtIdMapping(gt)
|
||
|
}
|
||
|
errRecord.AddError("构建id映射表错误: 没有数据")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// 构建城轨id映射
|
||
|
func BuildCgIdMapping(cg *dto.CGData, errRecord *ErrorRecord) *IdMapping {
|
||
|
if cg == nil {
|
||
|
errRecord.AddError("构建城轨id映射表错误: 未关联任何数据")
|
||
|
return nil
|
||
|
}
|
||
|
idMapping := &IdMapping{
|
||
|
deidMap: make(map[string]*idMap),
|
||
|
uidMap: make(map[string]*idMap),
|
||
|
}
|
||
|
lineSet := make(map[string]struct{})
|
||
|
for _, l := range cg.Lines {
|
||
|
if _, ok := lineSet[l.City+l.LineId]; ok {
|
||
|
errRecord.AddError(fmt.Sprintf("构建城轨id映射表错误: 线路重复:%s_%s", l.City, l.LineId))
|
||
|
return nil
|
||
|
}
|
||
|
lineSet[l.City+l.LineId] = struct{}{}
|
||
|
}
|
||
|
for _, line := range cg.Lines {
|
||
|
buildXhbz(idMapping, line, errRecord)
|
||
|
if errRecord.HasError() {
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
return idMapping
|
||
|
}
|
||
|
|
||
|
// 构建信号布置数据id映射
|
||
|
func buildXhbz(idMapping *IdMapping, line *dto.Line, errRecord *ErrorRecord) {
|
||
|
xhbz := line.Xhbz
|
||
|
if xhbz == nil {
|
||
|
errRecord.AddError("构建城轨id映射表错误: 信号布置数据为空")
|
||
|
return
|
||
|
}
|
||
|
city := line.City // 城市
|
||
|
lineId := line.LineId // 线路id
|
||
|
did := xhbz.Id // 数据id
|
||
|
errPrefix := "信号布置数据错误"
|
||
|
// 车站uid
|
||
|
for _, station := range xhbz.Stations {
|
||
|
eid := station.Id
|
||
|
if checkFieldEmpty(did, eid, station.Name, errPrefix, "车站名称", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, station.Name))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 车站站台uid
|
||
|
for _, p := range xhbz.Platforms {
|
||
|
eid := p.Id
|
||
|
if checkFieldEmpty(did, eid, p.Code, errPrefix, "站台编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, p.StationId, errPrefix, "站台关联车站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
stationIdm := idMapping.queryByDidAndEid(did, p.StationId)
|
||
|
if checkRelationNil(did, eid, p.StationId, stationIdm, errPrefix, "站台关联车站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
// 站台code: 车站名称_站台编号
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, stationIdm.Uid.Code(), p.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 屏蔽门uid
|
||
|
for _, p := range xhbz.Psds {
|
||
|
eid := p.Id
|
||
|
if checkFieldEmpty(did, eid, p.Code, errPrefix, "屏蔽门编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, p.PlatformId, errPrefix, "屏蔽门关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, p.PlatformId)
|
||
|
if checkRelationNil(did, eid, p.PlatformId, relIdMap, errPrefix, "屏蔽门关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
// 屏蔽门code: 站台编号_屏蔽门编号
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), p.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 物理区段
|
||
|
for _, ps := range xhbz.PhysicalSections {
|
||
|
eid := ps.Id
|
||
|
if checkFieldEmpty(did, eid, ps.Code, errPrefix, "物理区段编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, ps.EcsId, errPrefix, "物理区段关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, ps.EcsId)
|
||
|
if checkRelationNil(did, eid, ps.EcsId, relIdMap, errPrefix, "物理区段关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
// 物理区段code: 集中站名称_物理区段编号
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), ps.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 道岔uid
|
||
|
for _, t := range xhbz.Turnouts {
|
||
|
eid := t.Id
|
||
|
if checkFieldEmpty(did, eid, t.Code, errPrefix, "道岔编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, t.EcsId, errPrefix, "道岔关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, t.EcsId)
|
||
|
if checkRelationNil(did, eid, t.EcsId, relIdMap, errPrefix, "道岔关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
// 道岔code: 集中站名称_道岔编号
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), t.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 区段分界点uid
|
||
|
for _, c := range xhbz.DevidingPoints {
|
||
|
eid := c.Id
|
||
|
if checkFieldEmpty(did, eid, c.Code, errPrefix, "区段分界点编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, c.EcsIds, errPrefix, "区段分界点关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
ecsErr := false
|
||
|
for _, v := range c.EcsIds {
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v)
|
||
|
if checkRelationNil(did, eid, v, relIdMap, errPrefix, "区段分界点关联集中站", errRecord) {
|
||
|
ecsErr = true
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
if ecsErr {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, c.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 信号机uid
|
||
|
for _, s := range xhbz.Signals {
|
||
|
eid := s.Id
|
||
|
if checkFieldEmpty(did, eid, s.Code, errPrefix, "信号机编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, s.EcsId, errPrefix, "信号机关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, s.EcsId)
|
||
|
if checkRelationNil(did, eid, s.EcsId, relIdMap, errPrefix, "信号机关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), s.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 应答器uid
|
||
|
for _, b := range xhbz.Balises {
|
||
|
eid := b.Id
|
||
|
if checkFieldEmpty(did, eid, b.Code, errPrefix, "应答器编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, b.EcsId, errPrefix, "应答器关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, b.EcsId)
|
||
|
if checkRelationNil(did, eid, b.EcsId, relIdMap, errPrefix, "应答器关联集中站", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), b.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 停车点
|
||
|
for _, ps := range xhbz.ParkingSpots {
|
||
|
idmap := NewIdMap(did, ps.Id, NewCgUid(city, lineId, did, strconv.Itoa(int(ps.Id))))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 坡度
|
||
|
for _, v := range xhbz.Pds {
|
||
|
idmap := NewIdMap(did, v.Id, NewCgUid(city, lineId, did, strconv.Itoa(int(v.Id))))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 曲度
|
||
|
for _, v := range xhbz.Qds {
|
||
|
idmap := NewIdMap(did, v.Id, NewCgUid(city, lineId, did, strconv.Itoa(int(v.Id))))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 紧急停车按钮
|
||
|
for _, v := range xhbz.Emps {
|
||
|
eid := v.Id
|
||
|
if checkFieldEmpty(did, eid, v.Code, errPrefix, "紧急停车按钮编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, v.PlatformId, errPrefix, "紧急停车按钮关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v.PlatformId)
|
||
|
if checkRelationNil(did, eid, v.PlatformId, relIdMap, errPrefix, "紧急停车按钮关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), v.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 停车倒计时器
|
||
|
for _, v := range xhbz.Tdts {
|
||
|
eid := v.Id
|
||
|
if checkFieldEmpty(did, eid, v.Code, errPrefix, "停车倒计时器编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, v.PlatformId, errPrefix, "停车倒计时器关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v.PlatformId)
|
||
|
if checkRelationNil(did, eid, v.PlatformId, relIdMap, errPrefix, "停车倒计时器关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), v.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// 门控箱
|
||
|
for _, v := range xhbz.Mkxs {
|
||
|
eid := v.Id
|
||
|
if checkFieldEmpty(did, eid, v.Code, errPrefix, "门控箱编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, v.PsdId, errPrefix, "门控箱关联屏蔽门", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v.PsdId)
|
||
|
if checkRelationNil(did, eid, v.PsdId, relIdMap, errPrefix, "门控箱关联屏蔽门", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), v.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// PSL
|
||
|
for _, v := range xhbz.Psls {
|
||
|
eid := v.Id
|
||
|
if checkFieldEmpty(did, eid, v.Code, errPrefix, "PSL编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, v.PsdId, errPrefix, "PSL关联屏蔽门", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v.PsdId)
|
||
|
if checkRelationNil(did, eid, v.PsdId, relIdMap, errPrefix, "PSL关联屏蔽门", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), v.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
// SPKS
|
||
|
for _, v := range xhbz.Spks {
|
||
|
eid := v.Id
|
||
|
if checkFieldEmpty(did, eid, v.Code, errPrefix, "SPKS编号", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
if checkFieldEmpty(did, eid, v.PlatformId, errPrefix, "SPKS关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
relIdMap := idMapping.queryByDidAndEid(did, v.PlatformId)
|
||
|
if checkRelationNil(did, eid, v.PlatformId, relIdMap, errPrefix, "SPKS关联站台", errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
idmap := NewIdMap(did, eid, NewCgUid(city, lineId, relIdMap.Uid.Code(), v.Code))
|
||
|
if checkRepeatOrAddIdMap(idmap, idMapping, errPrefix, errRecord) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func checkRelationNil(did string, eid uint32, relId uint32, relIdMap *idMap, prefix string, relTip string, errRecord *ErrorRecord) bool {
|
||
|
if relIdMap == nil {
|
||
|
errRecord.AddError(fmt.Sprintf("%s: %s不存在, 数据id=%s 数据元素id=%v 关联id=%v", prefix, relTip, did, eid, relId))
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// 检查字段是否为空
|
||
|
func checkFieldEmpty(did string, eid uint32, field any, prefix string, tip string, errRecord *ErrorRecord) bool {
|
||
|
if isFieldEmpty(field) {
|
||
|
errRecord.AddError(fmt.Sprintf("%s: %s不能为空, 数据id=%s 数据元素id=%v ", prefix, tip, did, eid))
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func isFieldEmpty(field any) bool {
|
||
|
if field == nil {
|
||
|
return true
|
||
|
}
|
||
|
vf := reflect.ValueOf(field)
|
||
|
switch vf.Kind() {
|
||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||
|
reflect.Float32, reflect.Float64:
|
||
|
return field == 0
|
||
|
case reflect.String:
|
||
|
return field == ""
|
||
|
case reflect.Slice, reflect.Map:
|
||
|
return vf.Len() == 0
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// 数据uid/deid重复检查
|
||
|
func checkRepeatOrAddIdMap(idm *idMap, idMapping *IdMapping, prefix string, errRecord *ErrorRecord) (repeated bool) {
|
||
|
if old := idMapping.queryByDeId(idm.DeId()); old != nil {
|
||
|
errRecord.AddError(fmt.Sprintf("%s,数据元素重复: 数据1=%s 数据2=%s,", prefix, old.Debug(), idm.Debug()))
|
||
|
repeated = true
|
||
|
} else if old, _ := idMapping.checkUidAndAdd(idm); old != nil {
|
||
|
errRecord.AddError(fmt.Sprintf("%s,数据重复: 数据1=%s 数据2=%s,", prefix, old.Debug(), idm.Debug()))
|
||
|
repeated = true
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func BuildGtIdMapping(gt *dto.GTData) *IdMapping {
|
||
|
panic("未实现")
|
||
|
}
|