package handler import ( "fmt" "math/rand" "net/http" "os" "path/filepath" "strings" "time" "github.com/gin-gonic/gin" ) const uploadDir = "uploads" const maxUploadBytes = 5 * 1024 * 1024 // 5MB var allowedTypes = map[string]bool{"image/jpeg": true, "image/png": true, "image/gif": true, "image/webp": true} // UploadPost POST /api/upload 上传图片(表单 file) func UploadPost(c *gin.Context) { file, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请选择要上传的文件"}) return } if file.Size > maxUploadBytes { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "文件大小不能超过5MB"}) return } ct := file.Header.Get("Content-Type") if !allowedTypes[ct] && !strings.HasPrefix(ct, "image/") { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "仅支持图片格式"}) return } ext := filepath.Ext(file.Filename) if ext == "" { ext = ".jpg" } folder := c.PostForm("folder") if folder == "" { folder = "avatars" } dir := filepath.Join(uploadDir, folder) _ = os.MkdirAll(dir, 0755) name := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomStrUpload(6), ext) dst := filepath.Join(dir, name) if err := c.SaveUploadedFile(file, dst); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "保存失败"}) return } url := "/" + filepath.ToSlash(filepath.Join(uploadDir, folder, name)) c.JSON(http.StatusOK, gin.H{"success": true, "url": url, "data": gin.H{"url": url, "fileName": name, "size": file.Size, "type": ct}}) } func randomStrUpload(n int) string { const letters = "abcdefghijklmnopqrstuvwxyz0123456789" b := make([]byte, n) for i := range b { b[i] = letters[rand.Intn(len(letters))] } return string(b) } // UploadDelete DELETE /api/upload func UploadDelete(c *gin.Context) { path := c.Query("path") if path == "" { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请指定 path"}) return } if !strings.HasPrefix(path, "/uploads/") && !strings.HasPrefix(path, "uploads/") { c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "无权限删除此文件"}) return } fullPath := strings.TrimPrefix(path, "/") if err := os.Remove(fullPath); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "error": "文件不存在或删除失败"}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": "删除成功"}) }