81 lines
2.4 KiB
Go
81 lines
2.4 KiB
Go
package handlers
|
||
|
||
import (
|
||
"net/http"
|
||
"strings"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
|
||
"mengyastore-backend/internal/models"
|
||
"mengyastore-backend/internal/storage"
|
||
)
|
||
|
||
type PublicHandler struct {
|
||
store *storage.ProductStore
|
||
}
|
||
|
||
func NewPublicHandler(store *storage.ProductStore) *PublicHandler {
|
||
return &PublicHandler{store: store}
|
||
}
|
||
|
||
// ListProducts 上架商品列表(公开字段,不含卡密与管理信息)。
|
||
// @Summary 获取上架商品列表
|
||
// @Description 返回当前处于「上架」状态的商品集合,仅包含前台展示所需字段(不含卡密、管理字段等)。无需登录。
|
||
// @Tags 公开
|
||
// @Produce json
|
||
// @Success 200 {object} SwaggerProductListBody
|
||
// @Failure 500 {object} SwaggerErrorBody
|
||
// @Router /api/products [get]
|
||
func (h *PublicHandler) ListProducts(c *gin.Context) {
|
||
items, err := h.store.ListActive()
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"data": sanitizeForPublic(items)})
|
||
}
|
||
|
||
// RecordProductView 记录商品浏览(去重策略由服务端指纹决定)。
|
||
// @Summary 记录商品浏览次数
|
||
// @Description 对指定商品增加浏览计数;是否计入由服务端对访客指纹去重策略决定,用于热门统计。路径参数为商品 ID。
|
||
// @Tags 公开
|
||
// @Produce json
|
||
// @Param id path string true "商品ID(路径)"
|
||
// @Success 200 {object} SwaggerProductViewWrap
|
||
// @Failure 404 {object} SwaggerErrorBody
|
||
// @Router /api/products/{id}/view [post]
|
||
func (h *PublicHandler) RecordProductView(c *gin.Context) {
|
||
id := c.Param("id")
|
||
fingerprint := buildViewerFingerprint(c)
|
||
product, counted, err := h.store.IncrementView(id, fingerprint)
|
||
if err != nil {
|
||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"data": gin.H{
|
||
"id": product.ID,
|
||
"viewCount": product.ViewCount,
|
||
"counted": counted,
|
||
},
|
||
})
|
||
}
|
||
|
||
func buildViewerFingerprint(c *gin.Context) string {
|
||
clientIP := strings.TrimSpace(c.ClientIP())
|
||
userAgent := strings.TrimSpace(c.GetHeader("User-Agent"))
|
||
language := strings.TrimSpace(c.GetHeader("Accept-Language"))
|
||
return clientIP + "|" + userAgent + "|" + language
|
||
}
|
||
|
||
func sanitizeForPublic(items []models.Product) []models.Product {
|
||
out := make([]models.Product, len(items))
|
||
for i, item := range items {
|
||
item.Codes = nil
|
||
item.FixedContent = ""
|
||
out[i] = item
|
||
}
|
||
return out
|
||
}
|
||
|