fix: ResolveChannelToSource使用ListRecognitionUnits替代ListDeviceAssignments,告警列表通道列显示摄像头名
This commit is contained in:
parent
b4ef331be8
commit
d5cf7bf4f9
@ -1830,3 +1830,22 @@ func intValue(v any) int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveChannelToSource maps an alarm channel (e.g. "src_52ef4499_alarm_violation")
|
||||
// to its video source name (e.g. "5跨主通道").
|
||||
func (s *ConfigPreviewService) ResolveChannelToSource(channel string) string {
|
||||
if s == nil {
|
||||
return channel
|
||||
}
|
||||
unitName := channel
|
||||
if idx := strings.LastIndex(channel, "_alarm_"); idx > 0 {
|
||||
unitName = channel[:idx]
|
||||
}
|
||||
units, _ := s.ListRecognitionUnits()
|
||||
for _, u := range units {
|
||||
if u.Name == unitName && u.VideoSourceRef != "" {
|
||||
return u.VideoSourceRef
|
||||
}
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
@ -595,7 +595,12 @@ func NewUI(discovery *service.DiscoveryService, registry *service.RegistryServic
|
||||
return ""
|
||||
}
|
||||
},
|
||||
"alarmChannelSource": alarmChannelSource,
|
||||
"alarmChannelSource": func(channel string) string {
|
||||
if len(preview) > 0 && preview[0] != nil {
|
||||
return preview[0].ResolveChannelToSource(channel)
|
||||
}
|
||||
return channel
|
||||
},
|
||||
"statusLabel": func(v string) string {
|
||||
switch strings.TrimSpace(v) {
|
||||
case "unacknowledged":
|
||||
@ -2580,24 +2585,12 @@ func (u *UI) pageAlarms(w http.ResponseWriter, r *http.Request) {
|
||||
// Build device name/IP maps and channel→source map for template
|
||||
data.AlarmDeviceNames = map[string]string{}
|
||||
data.AlarmDeviceIPs = map[string]string{}
|
||||
data.AlarmChannelSources = map[string]string{}
|
||||
for _, dev := range data.Devices {
|
||||
if dev != nil {
|
||||
data.AlarmDeviceNames[dev.DeviceID] = dev.DisplayName()
|
||||
data.AlarmDeviceIPs[dev.DeviceID] = dev.IP
|
||||
}
|
||||
}
|
||||
if u.preview != nil {
|
||||
if assignments, err := u.preview.ListDeviceAssignments(); err == nil {
|
||||
for _, a := range assignments {
|
||||
for _, ref := range a.RecognitionUnits {
|
||||
if unit, err := u.preview.GetRecognitionUnit(ref); err == nil && unit != nil && unit.VideoSourceRef != "" {
|
||||
data.AlarmChannelSources[unit.Name] = unit.VideoSourceRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate total pages and build page list: 1, ..., cur-2, cur-1, cur, cur+1, cur+2, ..., N
|
||||
if data.TotalAlarmCount > 0 {
|
||||
data.TotalAlarmPages = (data.TotalAlarmCount + perPage - 1) / perPage
|
||||
@ -2742,19 +2735,6 @@ func (u *UI) apiAlarmExport(w http.ResponseWriter, r *http.Request) {
|
||||
deviceMap[d.DeviceID] = d
|
||||
}
|
||||
}
|
||||
// Channel→source lookup (channel = recognition unit name)
|
||||
channelSources := map[string]string{}
|
||||
if u.preview != nil {
|
||||
if assignments, _ := u.preview.ListDeviceAssignments(); len(assignments) > 0 {
|
||||
for _, a := range assignments {
|
||||
for _, ref := range a.RecognitionUnits {
|
||||
if unit, err := u.preview.GetRecognitionUnit(ref); err == nil && unit != nil && unit.VideoSourceRef != "" {
|
||||
channelSources[unit.Name] = unit.VideoSourceRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/csv; charset=utf-8")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="alarms_%s_%s.csv"`, from, to))
|
||||
@ -2768,7 +2748,7 @@ func (u *UI) apiAlarmExport(w http.ResponseWriter, r *http.Request) {
|
||||
devName = dev.DisplayName()
|
||||
devIP = dev.IP
|
||||
}
|
||||
sourceName := alarmChannelSource(a.Channel, channelSources)
|
||||
sourceName := u.preview.ResolveChannelToSource(a.Channel)
|
||||
fmt.Fprintf(w, "%s,%s,%s,%s,%s,%s,%s\n",
|
||||
escapeCSV(formatAlarmTime(a.Timestamp)), escapeCSV(devName), escapeCSV(devIP), escapeCSV(sourceName),
|
||||
escapeCSV(alarmRuleLabel(a.RuleName)), escapeCSV(a.ObjectLabel),
|
||||
@ -2815,30 +2795,14 @@ func alarmStatusLabel(v string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// alarmChannelSource resolves an alarm channel (e.g. "cam1_alarm_violation") to its video source name.
|
||||
// The channel format is {instanceName}_alarm_{type}, where instanceName matches the recognition unit.
|
||||
func alarmChannelSource(channel string, sources map[string]string) string {
|
||||
// Try exact match first
|
||||
if src, ok := sources[channel]; ok {
|
||||
return src
|
||||
}
|
||||
// Strip suffix: cam1_alarm_violation → cam1
|
||||
if idx := strings.LastIndex(channel, "_alarm_"); idx > 0 {
|
||||
if src, ok := sources[channel[:idx]]; ok {
|
||||
return src
|
||||
}
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
func formatAlarmTime(t string) string {
|
||||
// 2026-07-22T13:03:20+08:00 → 2026-07-22 13:03:20
|
||||
s := strings.TrimSpace(t)
|
||||
s = strings.Replace(s, "T", " ", 1)
|
||||
if idx := strings.Index(s, "+"); idx > 0 {
|
||||
s = s[:idx]
|
||||
if idx := strings.LastIndex(s, "+"); idx > 10 {
|
||||
s = strings.TrimSpace(s[:idx])
|
||||
}
|
||||
return strings.TrimSpace(s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (u *UI) pageResources(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
<a href="/devices/{{.DeviceID}}">{{index $.AlarmDeviceNames .DeviceID}}</a>
|
||||
<div class="muted small mono">{{index $.AlarmDeviceIPs .DeviceID}}</div>
|
||||
</td>
|
||||
<td>{{alarmChannelSource .Channel $.AlarmChannelSources}}</td>
|
||||
<td>{{alarmChannelSource .Channel}}</td>
|
||||
<td>
|
||||
<span class="pill warn">{{ruleLabel .RuleName}}</span>
|
||||
</td>
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user