From 8b85d5623a1c2d57dc94ee5723d00496d25e18ea Mon Sep 17 00:00:00 2001 From: chiyi Date: Tue, 27 Oct 2026 15:57:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(showcase):=20=E5=8E=BB=E6=8E=89=20Bento=20?= =?UTF-8?q?=E7=81=B5=E6=84=9F=E7=B1=BB=E5=9E=8B=EF=BC=8C=E5=8F=AA=E4=BF=9D?= =?UTF-8?q?=E7=95=99=20hero=20/=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端校验、分组、后台列表,以及后台页面与首页取图都只认 hero 和 work;启动时清掉遗留的 bento 记录。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- backend/internal/bootstrap/app.go | 4 +++ backend/internal/http/handler/showcase.go | 6 ++--- backend/internal/repo/showcase_repo.go | 5 ++-- backend/internal/service/admin_write.go | 6 ++--- frontend/src/views/HomeView.vue | 4 +-- frontend/src/views/ShowcaseView.vue | 31 +++++------------------ 6 files changed, 20 insertions(+), 36 deletions(-) diff --git a/backend/internal/bootstrap/app.go b/backend/internal/bootstrap/app.go index 7b97227..157cb3c 100644 --- a/backend/internal/bootstrap/app.go +++ b/backend/internal/bootstrap/app.go @@ -72,6 +72,10 @@ func NewApp(ctx context.Context) (*App, error) { if err := db.WithContext(ctx).Exec(`ALTER TABLE model_configs DROP COLUMN IF EXISTS enabled`).Error; err != nil { return nil, fmt.Errorf("drop model_configs.enabled: %w", err) } + // 首页展示位不再支持 bento,清掉遗留记录。 + if err := db.WithContext(ctx).Exec(`DELETE FROM showcase_items WHERE kind = 'bento'`).Error; err != nil { + return nil, fmt.Errorf("purge bento showcase: %w", err) + } if err := seedDefaults(ctx, db); err != nil { return nil, fmt.Errorf("seed defaults: %w", err) } diff --git a/backend/internal/http/handler/showcase.go b/backend/internal/http/handler/showcase.go index c58432e..6e7db0a 100644 --- a/backend/internal/http/handler/showcase.go +++ b/backend/internal/http/handler/showcase.go @@ -46,16 +46,16 @@ func (h *ShowcaseHandler) List(c *gin.Context) { // AdminList is the paginated flat view for the admin 首页内容 page — the public // List keeps its grouped shape for the home page, this one adds kind filter + -// limit/offset/total. Order mirrors the old client flattening: hero → bento → work. +// limit/offset/total. Order mirrors the old client flattening: hero → work. func (h *ShowcaseHandler) AdminList(c *gin.Context) { grouped, err := h.showcase.Grouped(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load showcase"}) return } - kindFilter := c.Query("kind") // "" | hero | bento | work + kindFilter := c.Query("kind") // "" | hero | work flat := make([]gin.H, 0, 16) - for _, kind := range []string{"hero", "bento", "work"} { + for _, kind := range []string{"hero", "work"} { if kindFilter != "" && kind != kindFilter { continue } diff --git a/backend/internal/repo/showcase_repo.go b/backend/internal/repo/showcase_repo.go index a03ba17..164e95e 100644 --- a/backend/internal/repo/showcase_repo.go +++ b/backend/internal/repo/showcase_repo.go @@ -62,9 +62,8 @@ func (r *ShowcaseRepository) Grouped(ctx context.Context) (map[string][]model.Sh } grouped := map[string][]model.ShowcaseItem{ - "hero": {}, - "bento": {}, - "work": {}, + "hero": {}, + "work": {}, } for _, item := range items { grouped[item.Kind] = append(grouped[item.Kind], item) diff --git a/backend/internal/service/admin_write.go b/backend/internal/service/admin_write.go index e0ef5d0..54da694 100644 --- a/backend/internal/service/admin_write.go +++ b/backend/internal/service/admin_write.go @@ -292,7 +292,7 @@ func (s *AdminWriteService) DeleteUserAPIKey(ctx context.Context, userID, keyID func (s *AdminWriteService) CreateShowcase(ctx context.Context, body map[string]any) (*model.ShowcaseItem, error) { kind := normalizedShowcaseKind(stringValue(body["kind"])) if kind == "" { - return nil, errors.New("kind must be hero, bento or work") + return nil, errors.New("kind must be hero or work") } image := strings.TrimSpace(stringValue(body["image"])) if image == "" { @@ -333,7 +333,7 @@ func (s *AdminWriteService) UpdateShowcase(ctx context.Context, entryID string, if _, ok := body["kind"]; ok { kind := normalizedShowcaseKind(stringValue(body["kind"])) if kind == "" { - return nil, errors.New("kind must be hero, bento or work") + return nil, errors.New("kind must be hero or work") } patch["kind"] = kind } @@ -581,7 +581,7 @@ func normalizedStatus(status string) string { func normalizedShowcaseKind(kind string) string { switch strings.TrimSpace(kind) { - case "hero", "bento", "work": + case "hero", "work": return strings.TrimSpace(kind) default: return "" diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 0637bff..d17cfe6 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -233,8 +233,8 @@ onMounted(async () => { ]) onlineModels.value = (m.data?.data || []).filter(model => model.sellable) const data = sc.data?.data || {} - // hero 拼贴按 hero → bento → 作品墙兜底取图,保证首屏有图可看 - const pool = [...(data.hero || []), ...(data.bento || []), ...(data.work || [])] + // hero 拼贴按 hero → 作品墙兜底取图,保证首屏有图可看 + const pool = [...(data.hero || []), ...(data.work || [])] carouselItems.value = pool.filter(i => i.image).slice(0, 4) if (!carouselItems.value.length) carouselItems.value = FALLBACK_HERO inspireItems.value = (data.work || []).length ? data.work : FALLBACK_WORKS diff --git a/frontend/src/views/ShowcaseView.vue b/frontend/src/views/ShowcaseView.vue index 68bc73d..c4d9830 100644 --- a/frontend/src/views/ShowcaseView.vue +++ b/frontend/src/views/ShowcaseView.vue @@ -1,17 +1,16 @@ @@ -186,12 +184,10 @@ onMounted(refresh)
-
-
@@ -209,7 +205,6 @@ onMounted(refresh)
{{ rec.kind }} @@ -255,7 +250,7 @@ onMounted(refresh)

{{ form.id ? '编辑' : '新增' }} · - {{ form.kind === 'hero' ? 'Hero 卡片' : form.kind === 'bento' ? 'Bento 灵感' : '作品' }} + {{ form.kind === 'hero' ? 'Hero 卡片' : '作品' }}

-
@@ -315,7 +309,7 @@ onMounted(refresh)
- +
@@ -326,19 +320,6 @@ onMounted(refresh) - -
- -
- -
- -
-

{{ error }}