From c817b42ff7980f47b45e4e8e2c5ecebe27d18b9c Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sun, 26 Jul 2026 12:34:35 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20video=5Fsources=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=95=B4=E6=95=B0ID=E4=B8=BB=E9=94=AE=EF=BC=8C=E5=90=8D?= =?UTF-8?q?=E5=AD=97=E5=8F=AF=E8=87=AA=E7=94=B1=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/config_assets.go | 24 ++++++++++++++++++---- internal/storage/assets_repo.go | 29 +++++++++++++++------------ internal/web/ui.go | 29 +++++++++++++++++---------- internal/web/ui/templates/assets.html | 2 +- 4 files changed, 55 insertions(+), 29 deletions(-) diff --git a/internal/service/config_assets.go b/internal/service/config_assets.go index f72355c..8704ff7 100644 --- a/internal/service/config_assets.go +++ b/internal/service/config_assets.go @@ -108,6 +108,7 @@ type AlarmServiceConfig struct { } type ConfigVideoSourceAsset struct { + ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` SourceType string `json:"source_type"` @@ -824,7 +825,7 @@ func (s *ConfigPreviewService) GetVideoSource(name string) (*ConfigVideoSourceAs return item, nil } -func (s *ConfigPreviewService) SaveVideoSourceAsset(asset ConfigVideoSourceAsset) error { +func (s *ConfigPreviewService) SaveVideoSourceAsset(asset ConfigVideoSourceAsset, originalName string) error { if s == nil || s.assets == nil { return fmt.Errorf("基础配置仓库未初始化") } @@ -836,8 +837,7 @@ func (s *ConfigPreviewService) SaveVideoSourceAsset(asset ConfigVideoSourceAsset if sourceType == "" { return fmt.Errorf("视频源类型不能为空") } - urlValue := strings.TrimSpace(asset.Config.URL) - if urlValue == "" { + if strings.TrimSpace(asset.Config.URL) == "" { return fmt.Errorf("视频源地址不能为空") } raw := map[string]any{ @@ -860,7 +860,22 @@ func (s *ConfigPreviewService) SaveVideoSourceAsset(asset ConfigVideoSourceAsset if err != nil { return err } - return s.assets.SaveVideoSource(name, sourceType, strings.TrimSpace(asset.Area), strings.TrimSpace(asset.Description), string(body)) + if err := s.assets.SaveVideoSource(asset.ID, name, sourceType, strings.TrimSpace(asset.Area), strings.TrimSpace(asset.Description), string(body)); err != nil { + return err + } + // If renaming, update recognition units + originalName = strings.TrimSpace(originalName) + if originalName != "" && originalName != name { + units, _ := s.ListRecognitionUnits() + for _, u := range units { + if u.VideoSourceRef == originalName { + u.VideoSourceRef = name + ref := recognitionUnitRef(u.SceneTemplateName, u.Name) + s.SaveRecognitionUnit(u, ref) + } + } + } + return nil } func (s *ConfigPreviewService) RenameVideoSource(oldName, newName string) error { @@ -1708,6 +1723,7 @@ func videoSourceAssetFromRecord(record storage.VideoSourceRecord) (*ConfigVideoS sourceMap = configMap } item := &ConfigVideoSourceAsset{ + ID: record.ID, Name: firstString(raw["name"], record.Name), Path: repoAssetPath("video_sources", record.Name), SourceType: firstString(record.SourceType, stringValue(raw["source_type"])), diff --git a/internal/storage/assets_repo.go b/internal/storage/assets_repo.go index ee5cd06..5997221 100644 --- a/internal/storage/assets_repo.go +++ b/internal/storage/assets_repo.go @@ -29,6 +29,7 @@ type IntegrationServiceRecord struct { } type VideoSourceRecord struct { + ID int Name string SourceType string Area string @@ -113,21 +114,23 @@ ON CONFLICT(name) DO UPDATE SET return err } -func (r *AssetsRepo) SaveVideoSource(name string, sourceType string, area string, description string, bodyJSON string) error { +func (r *AssetsRepo) SaveVideoSource(id int, name string, sourceType string, area string, description string, bodyJSON string) error { if r == nil || r.db == nil { return nil } now := time.Now().Format(time.RFC3339) + if id > 0 { + // Update existing by ID + _, err := r.db.Exec(` +UPDATE video_sources SET name=?, source_type=?, area=?, description=?, body_json=?, updated_at=? +WHERE id=?`, name, sourceType, area, description, bodyJSON, now, id) + return err + } + // Insert new _, err := r.db.Exec(` INSERT INTO video_sources(name, source_type, area, description, body_json, created_at, updated_at) -VALUES(?, ?, ?, ?, ?, COALESCE((SELECT created_at FROM video_sources WHERE name = ?), ?), ?) -ON CONFLICT(name) DO UPDATE SET - source_type=excluded.source_type, - area=excluded.area, - description=excluded.description, - body_json=excluded.body_json, - updated_at=excluded.updated_at -`, name, sourceType, area, description, bodyJSON, name, now, now) +VALUES(?, ?, ?, ?, ?, ?, ?) +`, name, sourceType, area, description, bodyJSON, now, now) return err } @@ -211,7 +214,7 @@ func (r *AssetsRepo) ListVideoSources() ([]VideoSourceRecord, error) { return nil, nil } rows, err := r.db.Query(` -SELECT name, source_type, area, description, body_json, created_at, updated_at +SELECT id, name, source_type, area, description, body_json, created_at, updated_at FROM video_sources ORDER BY updated_at DESC, name ASC `) @@ -223,7 +226,7 @@ ORDER BY updated_at DESC, name ASC var out []VideoSourceRecord for rows.Next() { var item VideoSourceRecord - if err := rows.Scan(&item.Name, &item.SourceType, &item.Area, &item.Description, &item.BodyJSON, &item.CreatedAt, &item.UpdatedAt); err != nil { + if err := rows.Scan(&item.ID, &item.Name, &item.SourceType, &item.Area, &item.Description, &item.BodyJSON, &item.CreatedAt, &item.UpdatedAt); err != nil { return nil, err } out = append(out, item) @@ -317,10 +320,10 @@ func (r *AssetsRepo) GetVideoSource(name string) (*VideoSourceRecord, error) { } var item VideoSourceRecord err := r.db.QueryRow(` -SELECT name, source_type, area, description, body_json, created_at, updated_at +SELECT id, name, source_type, area, description, body_json, created_at, updated_at FROM video_sources WHERE name = ? -`, name).Scan(&item.Name, &item.SourceType, &item.Area, &item.Description, &item.BodyJSON, &item.CreatedAt, &item.UpdatedAt) +`, name).Scan(&item.ID, &item.Name, &item.SourceType, &item.Area, &item.Description, &item.BodyJSON, &item.CreatedAt, &item.UpdatedAt) if err == sql.ErrNoRows { return nil, nil } diff --git a/internal/web/ui.go b/internal/web/ui.go index 0403d4a..6219ba6 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -1488,7 +1488,7 @@ func (u *UI) actionWizardCreateSource(w http.ResponseWriter, r *http.Request) { FPS: "25", }, } - if err := u.preview.SaveVideoSourceAsset(asset); err != nil { + if err := u.preview.SaveVideoSourceAsset(asset, ""); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -3745,7 +3745,7 @@ func (u *UI) actionAssetVideoSourceSave(w http.ResponseWriter, r *http.Request) MountAngle: strings.TrimSpace(r.FormValue("mount_angle")), }, } - if err := u.preview.SaveVideoSourceAsset(asset); err != nil { + if err := u.preview.SaveVideoSourceAsset(asset, ""); err != nil { data := u.assetPageData("video-sources") data.Title = "资产管理" data.Error = err.Error() @@ -3755,16 +3755,23 @@ func (u *UI) actionAssetVideoSourceSave(w http.ResponseWriter, r *http.Request) u.render(w, r, "assets", data) return } - // Handle rename - originalName := strings.TrimSpace(r.FormValue("original_name")) - if originalName != "" && originalName != asset.Name { - if err := u.preview.RenameVideoSource(originalName, asset.Name); err != nil { - data := u.assetPageData("video-sources") - data.Error = err.Error() - u.render(w, r, "assets", data) - return + // Pass ID for update (0 = new) + if idStr := strings.TrimSpace(r.FormValue("id")); idStr != "" { + if id, err := strconv.Atoi(idStr); err == nil { + asset.ID = id } } + originalName := strings.TrimSpace(r.FormValue("original_name")) + if err := u.preview.SaveVideoSourceAsset(asset, originalName); err != nil { + data := u.assetPageData("video-sources") + data.Title = "资产管理" + data.Error = err.Error() + data.AssetVideoSource = &asset + data.AssetVideoSource.SourceTypeLabel = serviceVideoSourceTypeLabel(asset.SourceType) + data.AssetVideoSourceEditing = true + u.render(w, r, "assets", data) + return + } http.Redirect(w, r, "/assets/video-sources?msg="+urlQueryEscape("视频源已保存")+"&name="+url.PathEscape(asset.Name), http.StatusFound) } @@ -3887,7 +3894,7 @@ func (u *UI) actionVideoSourceCSVImport(w http.ResponseWriter, r *http.Request) FPS: fps, }, } - if err := u.preview.SaveVideoSourceAsset(asset); err != nil { + if err := u.preview.SaveVideoSourceAsset(asset, ""); err != nil { skipped++ continue } diff --git a/internal/web/ui/templates/assets.html b/internal/web/ui/templates/assets.html index 3e87e75..9389a2c 100644 --- a/internal/web/ui/templates/assets.html +++ b/internal/web/ui/templates/assets.html @@ -232,7 +232,7 @@ toggleIntegrationFields('{{.AssetIntegration.Type}}'); {{if .AssetVideoSource}}