fix: console only deploys changed devices; wizard shows display names and pre-checks features
This commit is contained in:
parent
c57ca0b5a0
commit
a0f22230cb
@ -1276,14 +1276,22 @@ func (u *UI) actionConsoleSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: build requests using form features (user intent) and
|
||||
// existing recognition unit video sources.
|
||||
// Step 2: build requests only for devices whose features actually changed.
|
||||
var requests []service.AutoConfigRequest
|
||||
for _, dev := range devices {
|
||||
if dev == nil || dev.DeviceID == "" {
|
||||
continue
|
||||
}
|
||||
features := formFeatures[dev.DeviceID]
|
||||
if len(features) == 0 {
|
||||
continue
|
||||
}
|
||||
// Skip if features haven't changed from what's already saved.
|
||||
if saved, err := u.preview.GetDeviceFeatures(dev.DeviceID); err == nil {
|
||||
if stringSlicesEqual(sortedCopy(features), sortedCopy(saved)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var sources []string
|
||||
if assignment, err := u.preview.GetDeviceAssignment(dev.DeviceID); err == nil && assignment != nil {
|
||||
for _, ref := range assignment.RecognitionUnits {
|
||||
@ -1451,15 +1459,56 @@ func (u *UI) apiWizardDeviceInfo(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if u.agent != nil && dev.Online {
|
||||
channels := queryAgentChannels(u.agent, dev)
|
||||
// Channels: use management DB for friendly names and RTSP URLs
|
||||
channels := queryDeviceChannelsFromDB(u.preview, deviceID)
|
||||
resp["channels"] = channels
|
||||
|
||||
caps := queryAgentCapabilities(u.agent, dev)
|
||||
resp["capabilities"] = caps
|
||||
|
||||
// Include currently enabled features from management DB
|
||||
if u.preview != nil {
|
||||
if enabled, err := u.preview.GetDeviceFeatures(deviceID); err == nil {
|
||||
resp["enabled_features"] = enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
func queryDeviceChannelsFromDB(preview *service.ConfigPreviewService, deviceID string) []map[string]string {
|
||||
if preview == nil {
|
||||
return nil
|
||||
}
|
||||
assignment, err := preview.GetDeviceAssignment(deviceID)
|
||||
if err != nil || assignment == nil {
|
||||
return nil
|
||||
}
|
||||
var channels []map[string]string
|
||||
for _, ref := range assignment.RecognitionUnits {
|
||||
unit, err := preview.GetRecognitionUnit(ref)
|
||||
if err != nil || unit == nil {
|
||||
continue
|
||||
}
|
||||
ch := map[string]string{
|
||||
"name": unit.Name,
|
||||
}
|
||||
if unit.DisplayName != "" {
|
||||
ch["display"] = unit.DisplayName
|
||||
} else {
|
||||
ch["display"] = unit.Name
|
||||
}
|
||||
if unit.VideoSourceRef != "" {
|
||||
src, err := preview.GetVideoSource(unit.VideoSourceRef)
|
||||
if err == nil && src != nil && src.Config.URL != "" {
|
||||
ch["rtsp_url"] = src.Config.URL
|
||||
}
|
||||
}
|
||||
channels = append(channels, ch)
|
||||
}
|
||||
return channels
|
||||
}
|
||||
|
||||
func queryAgentChannels(agent *service.AgentClient, dev *models.Device) []map[string]string {
|
||||
body, code, err := agent.Do("GET", dev.IP, dev.AgentPort, "/v1/preview/channels", nil)
|
||||
if err != nil || code != 200 {
|
||||
@ -4488,6 +4537,28 @@ func cleanFormList(values []string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func sortedCopy(s []string) []string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
c := make([]string, len(s))
|
||||
copy(c, s)
|
||||
sort.Strings(c)
|
||||
return c
|
||||
}
|
||||
|
||||
func stringSlicesEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func parseDeviceAssignmentBoardState(raw string) (map[string][]string, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
|
||||
@ -200,11 +200,14 @@
|
||||
.then(function(r){return r.json()})
|
||||
.then(function(info){
|
||||
var channels = info.channels || [];
|
||||
step2Assigned = channels.map(function(ch){return {name: ch.name, url: ch.hls_url || ""}});
|
||||
step2Assigned = channels.map(function(ch){return {name: ch.display || ch.name, url: ch.rtsp_url || ""}});
|
||||
renderAssignedSources();
|
||||
|
||||
step2Features = [];
|
||||
var caps = (info.capabilities || []).filter(function(c){return c.available});
|
||||
// Pre-check features already enabled on this device
|
||||
var enabled = info.enabled_features || [];
|
||||
caps.forEach(function(c){ if (enabled.indexOf(c.key) >= 0) step2Features.push(c.key); });
|
||||
document.getElementById("feature-placeholder").style.display = "none";
|
||||
renderFeatures(caps);
|
||||
})
|
||||
@ -360,8 +363,7 @@
|
||||
} else {
|
||||
resultDiv.innerHTML = '<div class="card" style="border-left:3px solid var(--green)"><div class="metric-label">'+
|
||||
'<span class="status-dot ok"></span><strong>部署成功</strong></div>'+
|
||||
'<div class="muted small" style="margin-top:6px">模板:'+result.template_name+' | 检测通道:'+result.units_created+' 个</div>'+
|
||||
'<a href="/alarms" class="btn primary" style="margin-top:8px;font-size:11px">查看告警</a></div>';
|
||||
'<div class="muted small" style="margin-top:6px">模板:'+result.template_name+' | 检测通道:'+result.units_created+' 个</div></div>';
|
||||
btn.style.display = "none";
|
||||
currentStep = 3;
|
||||
document.querySelectorAll(".wizard-step").forEach(function(el){el.classList.add("done")});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user