package handlers import ( "net/http" "strings" "time" "github.com/gin-gonic/gin" "query-database/api/internal/auth" ) type upsertProgressReq struct { ExerciseID string `json:"exerciseId"` DraftSQL string `json:"draftSql"` IsSolved bool `json:"isSolved"` } func (h *Handlers) UpsertProgress(c *gin.Context) { userID := auth.UserID(c) var req upsertProgressReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"message": "参数错误"}) return } if strings.TrimSpace(req.ExerciseID) == "" { c.JSON(http.StatusBadRequest, gin.H{"message": "exerciseId 不能为空"}) return } now := time.Now().UTC().Format(time.RFC3339) solved := 0 if req.IsSolved { solved = 1 } _, err := h.sqlite.Exec( `INSERT INTO progress (id, user_id, exercise_id, draft_sql, is_solved, updated_at) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(user_id, exercise_id) DO UPDATE SET draft_sql = excluded.draft_sql, is_solved = CASE WHEN progress.is_solved = 1 THEN 1 ELSE excluded.is_solved END, updated_at = excluded.updated_at`, uuidOrDeterministic(userID, req.ExerciseID), userID, req.ExerciseID, req.DraftSQL, solved, now, ) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"message": "保存失败"}) return } c.Status(http.StatusNoContent) } func uuidOrDeterministic(userID string, exerciseID string) string { return userID + ":" + exerciseID }