package handler import ( "net/http" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" "github.com/wangjia/jiu/backend/internal/model" ) type ErrorReportHandler struct{ db *gorm.DB } func NewErrorReportHandler(db *gorm.DB) *ErrorReportHandler { return &ErrorReportHandler{db: db} } type submitErrorRequest struct { ErrorType string `json:"error_type" binding:"required"` AppVersion string `json:"app_version"` Platform string `json:"platform"` Username string `json:"username"` ShopID uint64 `json:"shop_id"` ShopNo string `json:"shop_no"` Role string `json:"role"` ProductInfo string `json:"product_info"` ErrorMsg string `json:"error_msg" binding:"required"` StackTrace string `json:"stack_trace"` OccurredAt int64 `json:"occurred_at"` // Unix 毫秒 } // Submit POST /api/v1/public/errors func (h *ErrorReportHandler) Submit(c *gin.Context) { var req submitErrorRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } occurredAt := time.Now() if req.OccurredAt > 0 { occurredAt = time.UnixMilli(req.OccurredAt) } stack := req.StackTrace const maxStack = 4000 if len(stack) > maxStack { stack = stack[:maxStack] } report := model.ErrorReport{ ErrorType: req.ErrorType, AppVersion: req.AppVersion, Platform: req.Platform, Username: req.Username, ShopID: req.ShopID, ShopNo: req.ShopNo, Role: req.Role, ProductInfo: req.ProductInfo, ClientIP: c.ClientIP(), ErrorMsg: req.ErrorMsg, StackTrace: stack, OccurredAt: occurredAt, } if err := h.db.Create(&report).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "submit failed"}) return } c.JSON(http.StatusCreated, gin.H{"id": report.ID}) } // List GET /api/v1/admin/errors (superadmin only) func (h *ErrorReportHandler) List(c *gin.Context) { var q struct { ErrorType string `form:"error_type"` Username string `form:"username"` Platform string `form:"platform"` Page int `form:"page,default=1"` PageSize int `form:"page_size,default=50"` } if err := c.ShouldBindQuery(&q); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if q.PageSize <= 0 || q.PageSize > 200 { q.PageSize = 50 } if q.Page <= 0 { q.Page = 1 } db := h.db.Model(&model.ErrorReport{}) if q.ErrorType != "" { db = db.Where("error_type = ?", q.ErrorType) } if q.Username != "" { db = db.Where("username LIKE ?", "%"+q.Username+"%") } if q.Platform != "" { db = db.Where("platform = ?", q.Platform) } var total int64 db.Count(&total) var reports []model.ErrorReport db.Order("id DESC").Offset((q.Page - 1) * q.PageSize).Limit(q.PageSize).Find(&reports) c.JSON(http.StatusOK, gin.H{ "data": reports, "total": total, "page": q.Page, "page_size": q.PageSize, }) }