53f56ce086
- deploy.yml: tag 触发(v*.*.*),四阶段调脚本(compile/test/release/deploy) - manual.yml: workflow_dispatch 支持手动回滚,checkout 指定 tag - scripts/ci/compile.sh: 构建 Go 二进制 + Flutter Web,打包 dist/ - scripts/ci/test.sh: go test + flutter analyze - scripts/ci/release.sh: 解析 CHANGELOG.md → 更新 version.yaml → 创建 Forgejo Release - scripts/ci/deploy.sh: 从 Release 下载产物(自动/手动均可)→ 部署到 EC2 - CHANGELOG.md: Keep a Changelog 格式,初始 v1.0.0 条目 - backend: GetRelease 改读 version.yaml,移除 ENV 变量依赖 - backend/config/version.yaml: 重置为 v1.0.0 - web/download.html: 动态拉取 /api/v1/public/release 展示版本号和更新内容 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/wangjia/jiu/backend/internal/model"
|
|
)
|
|
|
|
type PublicHandler struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewPublicHandler(db *gorm.DB) *PublicHandler {
|
|
return &PublicHandler{db: db}
|
|
}
|
|
|
|
// GetProduct GET /api/v1/public/products/:public_id (no auth)
|
|
func (h *PublicHandler) GetProduct(c *gin.Context) {
|
|
publicID := c.Param("public_id")
|
|
|
|
var product model.Product
|
|
if err := h.db.Where("public_id = ? AND deleted_at IS NULL", publicID).
|
|
Preload("Images").
|
|
First(&product).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
|
return
|
|
}
|
|
|
|
// Fetch shop public info
|
|
var shop model.Shop
|
|
shopData := gin.H{}
|
|
if err := h.db.Where("id = ?", product.ShopID).First(&shop).Error; err == nil {
|
|
shopData = gin.H{
|
|
"name": shop.Name,
|
|
"code": shop.Code,
|
|
"address": shop.Address,
|
|
"phone": shop.Phone,
|
|
"business_hours": shop.BusinessHours,
|
|
}
|
|
}
|
|
|
|
// Fetch latest inventory batch for this product
|
|
var inv model.Inventory
|
|
batchData := gin.H(nil)
|
|
if err := h.db.Where("product_id = ? AND quantity > 0 AND deleted_at IS NULL", product.ID).
|
|
Order("created_at DESC").
|
|
First(&inv).Error; err == nil {
|
|
var pdStr *string
|
|
if inv.ProductionDate != nil {
|
|
s := inv.ProductionDate.Time.Format("2006-01-02")
|
|
pdStr = &s
|
|
}
|
|
batchData = gin.H{
|
|
"production_date": pdStr,
|
|
"batch_no": inv.BatchNo,
|
|
"in_stock_date": inv.CreatedAt.Format("2006-01-02"),
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"data": gin.H{
|
|
"id": product.ID,
|
|
"name": product.Name,
|
|
"series": product.Series,
|
|
"spec": product.Spec,
|
|
"brand": product.Brand,
|
|
"unit": product.Unit,
|
|
"description": product.Description,
|
|
"images": product.Images,
|
|
"shop": shopData,
|
|
"batch": batchData,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetRelease GET /api/v1/public/release (no auth)
|
|
func (h *PublicHandler) GetRelease(c *gin.Context) {
|
|
cfg, err := loadVersionConfig()
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"version": "1.0.0",
|
|
"release_notes": "",
|
|
"download_urls": gin.H{"web": "https://jiu.51yanmei.com/app"},
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"version": cfg.Version,
|
|
"release_notes": cfg.ReleaseNotes,
|
|
"download_urls": cfg.DownloadURLs,
|
|
})
|
|
}
|