From 9c2a5d5cd8cac6682013177b0466a6f65d1e7253 Mon Sep 17 00:00:00 2001 From: hanxuanyu <2252193204@qq.com> Date: Tue, 27 Jan 2026 13:52:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=9B=B4=E5=A4=9A=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=85=83=E6=95=B0=E6=8D=AE=E5=B9=B6=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs.go | 67 +++++++++++++++++++++++++---- docs/swagger.json | 67 +++++++++++++++++++++++++---- docs/swagger.yaml | 48 +++++++++++++++++---- internal/http/handlers/image.go | 42 ++++++++++++++---- internal/model/models.go | 24 ++++++----- internal/service/fetcher/fetcher.go | 15 ++++--- webapp/doc/swagger.json | 67 +++++++++++++++++++++++++---- webapp/src/lib/api-types.ts | 5 +++ webapp/src/views/ApiDocs.vue | 41 +++++++++++++++++- webapp/src/views/Home.vue | 16 +++---- webapp/src/views/ImageView.vue | 11 ++--- 11 files changed, 331 insertions(+), 72 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 5429901..4a1d22b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -461,8 +461,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -518,8 +517,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -575,8 +573,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -607,8 +604,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -885,6 +881,61 @@ const docTemplate = `{ } } }, + "handlers.ImageMetaResp": { + "type": "object", + "properties": { + "copyright": { + "type": "string" + }, + "copyrightlink": { + "type": "string" + }, + "date": { + "type": "string" + }, + "fullstartdate": { + "type": "string" + }, + "hsh": { + "type": "string" + }, + "quiz": { + "type": "string" + }, + "startdate": { + "type": "string" + }, + "title": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.ImageVariantResp" + } + } + } + }, + "handlers.ImageVariantResp": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "storage_key": { + "type": "string" + }, + "url": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, "handlers.LoginRequest": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 331d5b4..ab04513 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -455,8 +455,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -512,8 +511,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -569,8 +567,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -601,8 +598,7 @@ "schema": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -879,6 +875,61 @@ } } }, + "handlers.ImageMetaResp": { + "type": "object", + "properties": { + "copyright": { + "type": "string" + }, + "copyrightlink": { + "type": "string" + }, + "date": { + "type": "string" + }, + "fullstartdate": { + "type": "string" + }, + "hsh": { + "type": "string" + }, + "quiz": { + "type": "string" + }, + "startdate": { + "type": "string" + }, + "title": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.ImageVariantResp" + } + } + } + }, + "handlers.ImageVariantResp": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "storage_key": { + "type": "string" + }, + "url": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, "handlers.LoginRequest": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 7044fbc..44bbe96 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -178,6 +178,42 @@ definitions: required: - name type: object + handlers.ImageMetaResp: + properties: + copyright: + type: string + copyrightlink: + type: string + date: + type: string + fullstartdate: + type: string + hsh: + type: string + quiz: + type: string + startdate: + type: string + title: + type: string + variants: + items: + $ref: '#/definitions/handlers.ImageVariantResp' + type: array + type: object + handlers.ImageVariantResp: + properties: + format: + type: string + size: + type: integer + storage_key: + type: string + url: + type: string + variant: + type: string + type: object handlers.LoginRequest: properties: password: @@ -500,8 +536,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/handlers.ImageMetaResp' summary: 获取指定日期图片元数据 tags: - image @@ -538,8 +573,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/handlers.ImageMetaResp' summary: 获取随机图片元数据 tags: - image @@ -576,8 +610,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/handlers.ImageMetaResp' summary: 获取今日图片元数据 tags: - image @@ -597,8 +630,7 @@ paths: description: OK schema: items: - additionalProperties: true - type: object + $ref: '#/definitions/handlers.ImageMetaResp' type: array summary: 获取图片列表 tags: diff --git a/internal/http/handlers/image.go b/internal/http/handlers/image.go index 34baf27..cc77710 100644 --- a/internal/http/handlers/image.go +++ b/internal/http/handlers/image.go @@ -16,6 +16,26 @@ import ( "go.uber.org/zap" ) +type ImageVariantResp struct { + Variant string `json:"variant"` + Format string `json:"format"` + Size int64 `json:"size"` + URL string `json:"url"` + StorageKey string `json:"storage_key"` +} + +type ImageMetaResp struct { + Date string `json:"date"` + Title string `json:"title"` + Copyright string `json:"copyright"` + CopyrightLink string `json:"copyrightlink"` + Quiz string `json:"quiz"` + StartDate string `json:"startdate"` + FullStartDate string `json:"fullstartdate"` + HSH string `json:"hsh"` + Variants []ImageVariantResp `json:"variants"` +} + // GetToday 获取今日图片 // @Summary 获取今日图片 // @Description 根据参数返回今日必应图片流或重定向 @@ -39,7 +59,7 @@ func GetToday(c *gin.Context) { // @Description 获取今日必应图片的标题、版权等元数据 // @Tags image // @Produce json -// @Success 200 {object} map[string]interface{} +// @Success 200 {object} ImageMetaResp // @Router /image/today/meta [get] func GetTodayMeta(c *gin.Context) { img, err := image.GetTodayImage() @@ -73,7 +93,7 @@ func GetRandom(c *gin.Context) { // @Description 随机获取一张已抓取图片的元数据 // @Tags image // @Produce json -// @Success 200 {object} map[string]interface{} +// @Success 200 {object} ImageMetaResp // @Router /image/random/meta [get] func GetRandomMeta(c *gin.Context) { img, err := image.GetRandomImage() @@ -110,7 +130,7 @@ func GetByDate(c *gin.Context) { // @Tags image // @Param date path string true "日期 (yyyy-mm-dd)" // @Produce json -// @Success 200 {object} map[string]interface{} +// @Success 200 {object} ImageMetaResp // @Router /image/date/{date}/meta [get] func GetByDateMeta(c *gin.Context) { date := c.Param("date") @@ -128,7 +148,7 @@ func GetByDateMeta(c *gin.Context) { // @Tags image // @Param limit query int false "限制数量" default(30) // @Produce json -// @Success 200 {array} map[string]interface{} +// @Success 200 {array} ImageMetaResp // @Router /images [get] func ListImages(c *gin.Context) { limitStr := c.DefaultQuery("limit", "30") @@ -232,10 +252,14 @@ func formatMeta(img *model.Image) gin.H { } return gin.H{ - "date": img.Date, - "title": img.Title, - "copyright": img.Copyright, - "quiz": img.Quiz, - "variants": variants, + "date": img.Date, + "title": img.Title, + "copyright": img.Copyright, + "copyrightlink": img.CopyrightLink, + "quiz": img.Quiz, + "startdate": img.StartDate, + "fullstartdate": img.FullStartDate, + "hsh": img.HSH, + "variants": variants, } } diff --git a/internal/model/models.go b/internal/model/models.go index 84f46e5..614e07d 100644 --- a/internal/model/models.go +++ b/internal/model/models.go @@ -7,16 +7,20 @@ import ( ) type Image struct { - ID uint `gorm:"primaryKey" json:"id"` - Date string `gorm:"uniqueIndex;type:varchar(10)" json:"date"` // YYYY-MM-DD - Title string `json:"title"` - Copyright string `json:"copyright"` - URLBase string `json:"urlbase"` - Quiz string `json:"quiz"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` - Variants []ImageVariant `gorm:"foreignKey:ImageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"variants"` + ID uint `gorm:"primaryKey" json:"id"` + Date string `gorm:"uniqueIndex;type:varchar(10)" json:"date"` // YYYY-MM-DD + Title string `json:"title"` + Copyright string `json:"copyright"` + CopyrightLink string `json:"copyrightlink"` + URLBase string `json:"urlbase"` + Quiz string `json:"quiz"` + StartDate string `json:"startdate"` + FullStartDate string `json:"fullstartdate"` + HSH string `json:"hsh"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` + Variants []ImageVariant `gorm:"foreignKey:ImageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"variants"` } type ImageVariant struct { diff --git a/internal/service/fetcher/fetcher.go b/internal/service/fetcher/fetcher.go index 535fa8d..f2e6fe5 100644 --- a/internal/service/fetcher/fetcher.go +++ b/internal/service/fetcher/fetcher.go @@ -38,6 +38,7 @@ type BingImage struct { CopyrightLink string `json:"copyrightlink"` Title string `json:"title"` Quiz string `json:"quiz"` + HSH string `json:"hsh"` } type Fetcher struct { @@ -111,11 +112,15 @@ func (f *Fetcher) processImage(ctx context.Context, bingImg BingImage) error { // 创建 DB 记录 dbImg := model.Image{ - Date: dateStr, - Title: bingImg.Title, - Copyright: bingImg.Copyright, - URLBase: bingImg.URLBase, - Quiz: bingImg.Quiz, + Date: dateStr, + Title: bingImg.Title, + Copyright: bingImg.Copyright, + CopyrightLink: bingImg.CopyrightLink, + URLBase: bingImg.URLBase, + Quiz: bingImg.Quiz, + StartDate: bingImg.Startdate, + FullStartDate: bingImg.Fullstartdate, + HSH: bingImg.HSH, } if err := repo.DB.Clauses(clause.OnConflict{ diff --git a/webapp/doc/swagger.json b/webapp/doc/swagger.json index 331d5b4..ab04513 100644 --- a/webapp/doc/swagger.json +++ b/webapp/doc/swagger.json @@ -455,8 +455,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -512,8 +511,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -569,8 +567,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -601,8 +598,7 @@ "schema": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/handlers.ImageMetaResp" } } } @@ -879,6 +875,61 @@ } } }, + "handlers.ImageMetaResp": { + "type": "object", + "properties": { + "copyright": { + "type": "string" + }, + "copyrightlink": { + "type": "string" + }, + "date": { + "type": "string" + }, + "fullstartdate": { + "type": "string" + }, + "hsh": { + "type": "string" + }, + "quiz": { + "type": "string" + }, + "startdate": { + "type": "string" + }, + "title": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.ImageVariantResp" + } + } + } + }, + "handlers.ImageVariantResp": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "storage_key": { + "type": "string" + }, + "url": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, "handlers.LoginRequest": { "type": "object", "required": [ diff --git a/webapp/src/lib/api-types.ts b/webapp/src/lib/api-types.ts index b90acaa..53543ae 100644 --- a/webapp/src/lib/api-types.ts +++ b/webapp/src/lib/api-types.ts @@ -149,6 +149,11 @@ export interface ImageMeta { date?: string title?: string copyright?: string + copyrightlink?: string // 图片的详细版权链接(指向 Bing 搜索页面) + quiz?: string // 旧字段,保留向后兼容 + startdate?: string // 图片的发布开始日期(格式:YYYYMMDD) + fullstartdate?: string // 图片的完整发布时间(格式:YYYYMMDDHHMM) + hsh?: string // 图片的唯一哈希值 url?: string variant?: string format?: string diff --git a/webapp/src/views/ApiDocs.vue b/webapp/src/views/ApiDocs.vue index 6e0e061..2594821 100644 --- a/webapp/src/views/ApiDocs.vue +++ b/webapp/src/views/ApiDocs.vue @@ -294,7 +294,7 @@

获取图片的元数据信息(标题、版权、日期等),只返回 JSON 数据不返回图片

-
+
/image/today/meta - @@ -316,6 +316,45 @@ 图片列表(支持分页)
+ + +
+

响应字段说明

+
+
+ date + 图片日期(格式:YYYY-MM-DD) +
+
+ title + 图片标题 +
+
+ copyright + 版权信息 +
+
+ copyrightlink + 版权详情链接(指向 Bing 搜索页面)⭐ 新增 +
+
+ startdate + 发布开始日期(格式:YYYYMMDD)⭐ 新增 +
+
+ fullstartdate + 完整发布时间(格式:YYYYMMDDHHMM)⭐ 新增 +
+
+ hsh + 图片唯一哈希值 ⭐ 新增 +
+
+ quiz + 必应 quiz 链接(已废弃,建议使用 copyrightlink) +
+
+
diff --git a/webapp/src/views/Home.vue b/webapp/src/views/Home.vue index fcb69a6..c21cba4 100644 --- a/webapp/src/views/Home.vue +++ b/webapp/src/views/Home.vue @@ -40,8 +40,8 @@ 查看大图