fix: persist features only after pipeline success, not before
actionConsoleSave: 先跑流水线,成功后再存 DB。 空功能提交不再清空 DB,改为提示用户。
This commit is contained in:
parent
67e8c3617a
commit
418bf3c80b
@ -1128,30 +1128,26 @@ func (u *UI) actionConsoleSave(w http.ResponseWriter, r *http.Request) {
|
||||
u.ensureDevicesLoaded()
|
||||
devices := u.registry.GetDevices()
|
||||
|
||||
// Step 1: persist feature selections to DB (source of truth).
|
||||
// Step 1: collect form features per device.
|
||||
formFeatures := map[string][]string{}
|
||||
for _, dev := range devices {
|
||||
if dev == nil || dev.DeviceID == "" {
|
||||
continue
|
||||
}
|
||||
features := cleanFormList(r.Form["device_"+dev.DeviceID+"_feature"])
|
||||
if err := u.preview.SaveDeviceFeatures(dev.DeviceID, features); err != nil {
|
||||
http.Redirect(w, r, "/ui/console?error="+url.QueryEscape("保存功能配置失败: "+err.Error()), http.StatusFound)
|
||||
return
|
||||
if len(features) > 0 {
|
||||
formFeatures[dev.DeviceID] = features
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: build requests from DB only.
|
||||
// Features come from device_features table.
|
||||
// Video sources come from existing device assignments and recognition units.
|
||||
// Step 2: build requests using form features (user intent) and
|
||||
// existing recognition unit video sources.
|
||||
var requests []service.AutoConfigRequest
|
||||
for _, dev := range devices {
|
||||
if dev == nil || dev.DeviceID == "" {
|
||||
continue
|
||||
}
|
||||
features, err := u.preview.GetDeviceFeatures(dev.DeviceID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
features := formFeatures[dev.DeviceID]
|
||||
var sources []string
|
||||
if assignment, err := u.preview.GetDeviceAssignment(dev.DeviceID); err == nil && assignment != nil {
|
||||
for _, ref := range assignment.RecognitionUnits {
|
||||
@ -1162,7 +1158,7 @@ func (u *UI) actionConsoleSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(features) == 0 && len(sources) == 0 {
|
||||
if len(features) == 0 {
|
||||
continue
|
||||
}
|
||||
requests = append(requests, service.AutoConfigRequest{
|
||||
@ -1173,12 +1169,22 @@ func (u *UI) actionConsoleSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if len(requests) == 0 {
|
||||
http.Redirect(w, r, "/ui/console?msg="+url.QueryEscape("未选择检测功能或未分配视频源"), http.StatusFound)
|
||||
http.Redirect(w, r, "/ui/console?msg="+url.QueryEscape("未选择检测功能"), http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
// Step 3: run pipeline. Only persist to DB on success.
|
||||
results, _ := u.autoConfig.BuildPipelineBatch(requests, true)
|
||||
|
||||
// Step 4: persist successful feature selections to DB.
|
||||
for _, res := range results {
|
||||
if res.Error == "" && res.TaskID != "" {
|
||||
if feats, ok := formFeatures[res.DeviceID]; ok {
|
||||
_ = u.preview.SaveDeviceFeatures(res.DeviceID, feats)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect task IDs for redirect.
|
||||
taskIDs := make([]string, 0)
|
||||
var errs []string
|
||||
|
||||
@ -356,6 +356,10 @@
|
||||
});
|
||||
});
|
||||
if (!summary) { alert('未选择任何检测功能或视频源'); return; }
|
||||
// Require at least one feature.
|
||||
var hasFeature = false;
|
||||
document.querySelectorAll('.console-device-row input[type=checkbox]:checked').forEach(function() { hasFeature = true; });
|
||||
if (!hasFeature) { alert('请至少选择一项检测功能'); return; }
|
||||
var overlay = document.createElement('div');
|
||||
overlay.className = 'confirm-overlay';
|
||||
overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:9999;display:flex;align-items:center;justify-content:center';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user