From d0a084b80e76124de3271d5aced573f221978436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8F=E7=8A=80=E9=BA=9F?= Date: Mon, 14 Sep 2026 01:48:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(wallpaper):=20=E5=B9=B3=E5=8F=B0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=84=B1=E6=95=8F=E5=9B=9E=E6=98=BE=20+=20=E5=9B=BE?= =?UTF-8?q?=E5=BA=93=E5=85=83=E5=AD=97=E6=AE=B5=E8=A1=A5=E9=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后台做完界面才发现的两个接口缺口: 1) 平台配置不回显 → 用户只改一个开关,defaultQuery / purity / baseUrl 会被一起清空(SaveSource 只对 apiKey/apiSecret 做了"留空即保留")。 现在 Sources() 返回脱敏后的 config(凭据一律置空,是否已设置由 HasApiKey 表达),前台接口不下发该字段 —— toAPISource 加 withConfig 开关,公开接口没必要泄露自建反代地址等内部信息。 2) Item 缺 enabled / sort / remark → 后台列表无法显示启用状态, 编辑抽屉也拿不到当前值。补齐字段并在 library.toItem 中填充, 开源平台条目保持默认值(这三个字段对前台无意义)。 另抽出 sanitizeSourceConfig 统一处理凭据抹除,避免以后再加配置项时漏抹。 --- api/wallpaper/wallpaper.go | 23 ++++++++++++- internal/controller/wallpaper/admin.go | 4 ++- internal/controller/wallpaper/controller.go | 21 ++++++++++-- internal/controller/wallpaper/open.go | 3 +- internal/model/dto/wallpaper.go | 38 +++++++++++++-------- internal/service/wallpaper/library.go | 3 ++ internal/service/wallpaper/source.go | 14 ++++++++ 7 files changed, 87 insertions(+), 19 deletions(-) diff --git a/api/wallpaper/wallpaper.go b/api/wallpaper/wallpaper.go index 604cadb..5a03ea0 100644 --- a/api/wallpaper/wallpaper.go +++ b/api/wallpaper/wallpaper.go @@ -36,7 +36,12 @@ type Item struct { Tags string `json:"tags"` Category string `json:"category"` Filesize int64 `json:"filesize"` - CreatedAt string `json:"createdAt"` + // Enabled / Sort / Remark 仅自建图库有值,供后台列表展示与就地编辑; + // 开源平台条目恒为默认值,前台不关心。 + Enabled int `json:"enabled"` + Sort int `json:"sort"` + Remark string `json:"remark"` + CreatedAt string `json:"createdAt"` } // SourceInfo 开源平台的可用性描述。 @@ -50,6 +55,22 @@ type SourceInfo struct { Hint string `json:"hint"` // 不可用原因 Remark string `json:"remark"` HasApiKey bool `json:"hasApiKey"` // 只回传「是否已设置」,不回传明文 + // Config 是脱敏后的平台配置,供后台编辑界面回显(前台接口不下发)。 + // apiKey / apiSecret 恒为空串 —— 提交时留空即表示「不修改已保存的 Key」。 + Config *SourceConfig `json:"config"` +} + +// SourceConfig 是平台可配置项,与 dto.WallpaperSourceConfig 一一对应。 +type SourceConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + DefaultQuery string `json:"defaultQuery"` + // Purity 分级过滤(Wallhaven):sfw / sketchy / nsfw,默认只放 sfw。 + Purity string `json:"purity"` + // Categories 分类(Wallhaven):general/anime/people 组合。 + Categories string `json:"categories"` + // BaseUrl 覆盖平台接口地址(自建反代或镜像)。 + BaseUrl string `json:"baseUrl"` } // --------------------------------------------------------------------------- diff --git a/internal/controller/wallpaper/admin.go b/internal/controller/wallpaper/admin.go index 658b17d..02d0395 100644 --- a/internal/controller/wallpaper/admin.go +++ b/internal/controller/wallpaper/admin.go @@ -167,7 +167,9 @@ func (c *Controller) SourceList(ctx context.Context, req *wallpaperv1.AdminSourc } out := make([]*wallpaperv1.SourceInfo, 0, len(list)) for i := range list { - out = append(out, toAPISource(&list[i])) + // 后台带配置:编辑界面需要回显 defaultQuery / purity / baseUrl 等, + // 否则用户只改开关也会把这些字段一并清空。 + out = append(out, toAPISource(&list[i], true)) } return &wallpaperv1.AdminSourceListRes{List: out}, nil } diff --git a/internal/controller/wallpaper/controller.go b/internal/controller/wallpaper/controller.go index 050b2d7..5a0cbee 100644 --- a/internal/controller/wallpaper/controller.go +++ b/internal/controller/wallpaper/controller.go @@ -37,6 +37,9 @@ func toAPIItem(v *dto.WallpaperItem) *wallpaperv1.Item { Tags: v.Tags, Category: v.Category, Filesize: v.Filesize, + Enabled: v.Enabled, + Sort: v.Sort, + Remark: v.Remark, CreatedAt: v.CreatedAt, } } @@ -51,8 +54,11 @@ func toAPIItems(list []dto.WallpaperItem) []*wallpaperv1.Item { } // toAPISource 把平台信息转成接口输出结构。 -func toAPISource(v *dto.WallpaperSourceInfo) *wallpaperv1.SourceInfo { - return &wallpaperv1.SourceInfo{ +// +// withConfig 控制是否下发脱敏后的配置:后台需要它回显,前台不需要 +// (自建反代地址之类属于内部信息,没必要给公网浏览器)。 +func toAPISource(v *dto.WallpaperSourceInfo, withConfig bool) *wallpaperv1.SourceInfo { + out := &wallpaperv1.SourceInfo{ Code: v.Code, Name: v.Name, Enabled: v.Enabled, @@ -63,4 +69,15 @@ func toAPISource(v *dto.WallpaperSourceInfo) *wallpaperv1.SourceInfo { Remark: v.Remark, HasApiKey: v.HasApiKey, } + if withConfig && v.Config != nil { + out.Config = &wallpaperv1.SourceConfig{ + ApiKey: v.Config.ApiKey, + ApiSecret: v.Config.ApiSecret, + DefaultQuery: v.Config.DefaultQuery, + Purity: v.Config.Purity, + Categories: v.Config.Categories, + BaseUrl: v.Config.BaseUrl, + } + } + return out } diff --git a/internal/controller/wallpaper/open.go b/internal/controller/wallpaper/open.go index 688e44c..8c2034b 100644 --- a/internal/controller/wallpaper/open.go +++ b/internal/controller/wallpaper/open.go @@ -37,7 +37,8 @@ func (c *OpenController) Sources(ctx context.Context, req *wallpaperv1.OpenSourc out := make([]*wallpaperv1.SourceInfo, 0, len(list)) for i := range list { - out = append(out, toAPISource(&list[i])) + // 前台不带平台配置:公开接口没必要下发 baseUrl 等内部信息。 + out = append(out, toAPISource(&list[i], false)) } return &wallpaperv1.OpenSourceListRes{List: out, MineCount: mineCount}, nil } diff --git a/internal/model/dto/wallpaper.go b/internal/model/dto/wallpaper.go index 89cd7e1..ed0b7d9 100644 --- a/internal/model/dto/wallpaper.go +++ b/internal/model/dto/wallpaper.go @@ -25,18 +25,23 @@ type WallpaperItem struct { PreviewUrl string `json:"previewUrl"` FullUrl string `json:"fullUrl"` // ---- 归属 ---- - Source string `json:"source"` // 平台编码,自建图库固定为 "mine" + Source string `json:"source"` // 平台编码,自建图库固定为 "mine" SourceName string `json:"sourceName"` // 平台显示名,用于界面标注 - FromOpen bool `json:"fromOpen"` // true=开源平台 false=自建图库 + FromOpen bool `json:"fromOpen"` // true=开源平台 false=自建图库 // ---- 版权信息(自建图库留空)---- Author string `json:"author"` AuthorUrl string `json:"authorUrl"` - PageUrl string `json:"pageUrl"` // 平台详情页,用于「查看原页面」 - License string `json:"license"` // 许可说明,如 "Unsplash License" + PageUrl string `json:"pageUrl"` // 平台详情页,用于「查看原页面」 + License string `json:"license"` // 许可说明,如 "Unsplash License" // ---- 自建图库专有 ---- - Tags string `json:"tags"` - Category string `json:"category"` - Filesize int64 `json:"filesize"` + Tags string `json:"tags"` + Category string `json:"category"` + Filesize int64 `json:"filesize"` + // Enabled / Sort / Remark 只有自建图库有值(开源平台条目恒为默认值), + // 后台列表要显示启用状态并支持就地编辑,前台不关心这三个字段。 + Enabled int `json:"enabled"` + Sort int `json:"sort"` + Remark string `json:"remark"` CreatedAt string `json:"createdAt"` } @@ -54,6 +59,11 @@ type WallpaperSourceInfo struct { Available bool `json:"available"` Hint string `json:"hint"` // 不可用原因,可用时为空 Remark string `json:"remark"` + // Config 是脱敏后的平台配置,供后台编辑界面回显。 + // apiKey / apiSecret 一律置空不回传明文,是否已设置由 HasApiKey 表达; + // 界面上留空提交即表示「不修改已保存的 Key」。 + // 前台接口不下发本字段(避免暴露自建反代地址等内部信息)。 + Config *WallpaperSourceConfig `json:"config"` // Config 是脱敏后的配置(apiKey 只回传是否已设置,不回传明文)。 HasApiKey bool `json:"hasApiKey"` } @@ -101,13 +111,13 @@ type WallpaperQuery struct { // WallpaperSaveInput 是后台编辑壁纸元数据的入参(不含文件本身)。 type WallpaperSaveInput struct { - Id uint64 `json:"id"` - Title string `json:"title"` - Tags string `json:"tags"` - Category string `json:"category"` - Enabled int `json:"enabled"` - Sort int `json:"sort"` - Remark string `json:"remark"` + Id uint64 `json:"id"` + Title string `json:"title"` + Tags string `json:"tags"` + Category string `json:"category"` + Enabled int `json:"enabled"` + Sort int `json:"sort"` + Remark string `json:"remark"` } // WallpaperStat 是图库概览统计。 diff --git a/internal/service/wallpaper/library.go b/internal/service/wallpaper/library.go index b203db3..41948f4 100644 --- a/internal/service/wallpaper/library.go +++ b/internal/service/wallpaper/library.go @@ -161,6 +161,9 @@ func (s *service) toItem(e *entity.Wallpaper) dto.WallpaperItem { Tags: e.Tags, Category: e.Category, Filesize: e.Filesize, + Enabled: e.Enabled, + Sort: e.Sort, + Remark: e.Remark, CreatedAt: e.CreatedAt, } } diff --git a/internal/service/wallpaper/source.go b/internal/service/wallpaper/source.go index 2992c2a..09a539f 100644 --- a/internal/service/wallpaper/source.go +++ b/internal/service/wallpaper/source.go @@ -48,6 +48,7 @@ func (s *service) Sources(ctx context.Context) ([]dto.WallpaperSourceInfo, error Configured: !p.RequiresKey(), Available: false, Hint: "尚未在后台启用", + Config: sanitizeSourceConfig(dto.WallpaperSourceConfig{}), }) continue } @@ -61,6 +62,7 @@ func (s *service) Sources(ctx context.Context) ([]dto.WallpaperSourceInfo, error Configured: configured, Available: e.Enabled == 1 && configured, Remark: e.Remark, + Config: sanitizeSourceConfig(cfg), HasApiKey: cfg.ApiKey != "", } switch { @@ -216,3 +218,15 @@ func ParseSourceConfig(raw string) dto.WallpaperSourceConfig { } return cfg } + +// sanitizeSourceConfig 生成可安全下发给前端的配置副本:抹掉全部凭据。 +// +// 后台需要它来「回显」用户此前填过的 defaultQuery / purity / baseUrl, +// 否则用户只想改个开关也会把这些字段一起清空; +// 但凭据明文不能出后端,故这里只清 apiKey / apiSecret, +// 是否已设置改由 HasApiKey 布尔表达。 +func sanitizeSourceConfig(cfg dto.WallpaperSourceConfig) *dto.WallpaperSourceConfig { + cfg.ApiKey = "" + cfg.ApiSecret = "" + return &cfg +}