From 6a63442dcf7f03620cbdbca5cf7be69893d3aa06 Mon Sep 17 00:00:00 2001 From: strive_qin Date: Wed, 16 Sep 2026 19:27:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(app):=20=E5=89=8D=E5=8F=B0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=A8=A1=E5=9E=8B=20-=20=E5=88=86=E8=BE=A8=E7=8E=87?= =?UTF-8?q?=E6=A1=A3=E4=BD=8D=E4=B8=8E=E5=90=84=E4=BE=9B=E5=BA=94=E7=BA=BF?= =?UTF-8?q?=E8=B7=AF=E5=8F=96=E5=B9=B6=E9=9B=86=EF=BC=8C=E4=BF=AE=E6=8E=89?= =?UTF-8?q?=E5=8F=AA=E6=98=BE=E7=A4=BA=E5=8D=95=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit capabilitySpecWithRoutePresets 原先只在「前台自身没有任何尺寸预设」时才与线路合并。但前台快照的预设往往来自单条线路(后续新增的供应线路还没同步进来),条件不成立后,其它线路的 2K/4K 预设永远补不进来,前台只显示 1K。 现在无论自身是否已有预设都与各线路取并集(mergeCapabilityImageSize 已包含前台自身的预设,并集不会丢档)。 线上数据可复现:image-2.0-1k 的前台规格 imageSize.presets 全部是 1k,而它四条线路分别是 none/none/1k/2k+4k。补了一条回归测试,反向验证确认旧逻辑下该测试精确报出 tier 2k missing。 --- backend/internal/app/logical_models.go | 30 +++++++++--------- backend/internal/app/logical_models_test.go | 34 +++++++++++++++++++++ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/backend/internal/app/logical_models.go b/backend/internal/app/logical_models.go index ef70947f6..37310481b 100644 --- a/backend/internal/app/logical_models.go +++ b/backend/internal/app/logical_models.go @@ -280,23 +280,21 @@ func capabilitySpecWithRoutePresets(spec CapabilitySpec, routes []CapabilitySpec } result.Options[name] = OptionConstraint{Values: values} } - if result.ImageSize == nil || result.ImageSize.Parameter == "" || len(result.ImageSize.Presets) == 0 { - if merged := mergeCapabilityImageSize(append([]CapabilitySpec{spec}, routes...)); merged != nil { - if result.ImageSize == nil { - result.ImageSize = merged - } else { - restored := *result.ImageSize - if restored.Parameter == "" { - restored.Parameter = merged.Parameter - } - if !restored.AllowCustom { - restored.AllowCustom = merged.AllowCustom - } - if len(restored.Presets) == 0 { - restored.Presets = merged.Presets - } - result.ImageSize = &restored + // 前台规格里的预设可能只来自单条线路的快照(后续新增的供应线路还没同步进来), + // 因此不管自身是否已有预设都要与各线路取并集,否则多档会被压成单档。 + if merged := mergeCapabilityImageSize(append([]CapabilitySpec{spec}, routes...)); merged != nil { + if result.ImageSize == nil { + result.ImageSize = merged + } else { + restored := *result.ImageSize + if restored.Parameter == "" { + restored.Parameter = merged.Parameter } + if !restored.AllowCustom { + restored.AllowCustom = merged.AllowCustom + } + restored.Presets = merged.Presets + result.ImageSize = &restored } } return result diff --git a/backend/internal/app/logical_models_test.go b/backend/internal/app/logical_models_test.go index 3d5aaccaf..c9793d083 100644 --- a/backend/internal/app/logical_models_test.go +++ b/backend/internal/app/logical_models_test.go @@ -26,6 +26,40 @@ func TestCapabilitySpecWithRoutePresetsRestoresImageSize(t *testing.T) { } } +func TestCapabilitySpecWithRoutePresetsUnionsTiersAcrossRoutes(t *testing.T) { + // 前台快照只带了单条线路的 1K 预设,其它线路提供 2K/4K:必须取并集,不能压成单档。 + preset := func(size string, tier string, width int, height int) CapabilityImageSizePreset { + return CapabilityImageSizePreset{Size: size, Tier: tier, Ratio: "16:9", Width: width, Height: height} + } + product := CapabilitySpec{ + Version: 1, + Capability: "image", + Options: map[string]OptionConstraint{"size": {Values: []any{"16:9"}}}, + ImageSize: &CapabilityImageSize{ + Parameter: "aspect_ratio", + Presets: []CapabilityImageSizePreset{preset("1824x1024", "1k", 1824, 1024)}, + }, + } + routes := []CapabilitySpec{ + {Version: 1, Capability: "image", ImageSize: &CapabilityImageSize{Parameter: "aspect_ratio", Presets: []CapabilityImageSizePreset{preset("2752x1536", "2k", 2752, 1536)}}}, + {Version: 1, Capability: "image", ImageSize: &CapabilityImageSize{Parameter: "aspect_ratio", Presets: []CapabilityImageSizePreset{preset("3840x2160", "4k", 3840, 2160)}}}, + } + + got := capabilitySpecWithRoutePresets(product, routes) + if got.ImageSize == nil { + t.Fatal("imageSize = nil") + } + tiers := make(map[string]bool, len(got.ImageSize.Presets)) + for _, item := range got.ImageSize.Presets { + tiers[item.Tier] = true + } + for _, tier := range []string{"1k", "2k", "4k"} { + if !tiers[tier] { + t.Fatalf("tier %s missing: %#v", tier, got.ImageSize.Presets) + } + } +} + func TestMatchCapabilityRoutesTextImagesOnlyToDeclaredProfiles(t *testing.T) { plainText := CapabilitySpec{ Version: 1,