From ab421f2185509ba30eec9174015e73aa690e8fe7 Mon Sep 17 00:00:00 2001 From: RockYang Date: Mon, 26 Aug 2024 17:59:05 +0800 Subject: [PATCH] luma page, upload image and remove image function is ready --- api/core/app_server.go | 110 ++++++++++++++++------------------ api/handler/upload_handler.go | 39 ++++++++++-- api/main.go | 5 +- web/public/images/loading.gif | Bin 0 -> 16618 bytes web/src/assets/css/luma.styl | 27 ++++++++- web/src/utils/http.js | 14 +++++ web/src/views/Luma.vue | 86 +++++++++++++++++++++----- 7 files changed, 200 insertions(+), 81 deletions(-) create mode 100644 web/public/images/loading.gif diff --git a/api/core/app_server.go b/api/core/app_server.go index fab16d1c..92967067 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -26,7 +26,6 @@ import ( "io" "net/http" "os" - "path/filepath" "runtime/debug" "strings" "time" @@ -228,6 +227,7 @@ func needLogin(c *gin.Context) bool { c.Request.URL.Path == "/api/suno/client" || c.Request.URL.Path == "/api/suno/detail" || c.Request.URL.Path == "/api/suno/play" || + c.Request.URL.Path == "/api/download" || strings.HasPrefix(c.Request.URL.Path, "/api/test") || strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") || strings.HasPrefix(c.Request.URL.Path, "/api/config/") || @@ -316,64 +316,58 @@ func staticResourceMiddleware() gin.HandlerFunc { url := c.Request.URL.String() // 拦截生成缩略图请求 - if strings.HasPrefix(url, "/static/") { - if strings.Contains(url, "?imageView2") { - r := strings.SplitAfter(url, "imageView2") - size := strings.Split(r[1], "/") - if len(size) != 8 { - c.String(http.StatusNotFound, "invalid thumb args") - return - } - with := utils.IntValue(size[3], 0) - height := utils.IntValue(size[5], 0) - quality := utils.IntValue(size[7], 75) - - // 打开图片文件 - filePath := strings.TrimLeft(c.Request.URL.Path, "/") - file, err := os.Open(filePath) - if err != nil { - c.String(http.StatusNotFound, "Image not found") - return - } - defer file.Close() - - // 解码图片 - img, _, err := image.Decode(file) - // for .webp image - if err != nil { - img, err = webp.Decode(file) - } - if err != nil { - c.String(http.StatusInternalServerError, "Error decoding image") - return - } - - var newImg image.Image - if height == 0 || with == 0 { - // 固定宽度,高度自适应 - newImg = resize.Resize(uint(with), uint(height), img, resize.Lanczos3) - } else { - // 生成缩略图 - newImg = resize.Thumbnail(uint(with), uint(height), img, resize.Lanczos3) - } - var buffer bytes.Buffer - err = jpeg.Encode(&buffer, newImg, &jpeg.Options{Quality: quality}) - if err != nil { - logger.Error(err) - c.String(http.StatusInternalServerError, err.Error()) - return - } - - // 设置图片缓存有效期为一年 (365天) - c.Header("Cache-Control", "max-age=31536000, public") - // 直接输出图像数据流 - c.Data(http.StatusOK, "image/jpeg", buffer.Bytes()) - c.Abort() // 中断请求 - } else if strings.Contains(url, "?download=true") { - filename := filepath.Base(url) - c.Header("Content-Disposition", "attachment; filename="+filename) - c.Header("Content-Type", "application/octet-stream") + if strings.HasPrefix(url, "/static/") && strings.Contains(url, "?imageView2") { + r := strings.SplitAfter(url, "imageView2") + size := strings.Split(r[1], "/") + if len(size) != 8 { + c.String(http.StatusNotFound, "invalid thumb args") + return } + with := utils.IntValue(size[3], 0) + height := utils.IntValue(size[5], 0) + quality := utils.IntValue(size[7], 75) + + // 打开图片文件 + filePath := strings.TrimLeft(c.Request.URL.Path, "/") + file, err := os.Open(filePath) + if err != nil { + c.String(http.StatusNotFound, "Image not found") + return + } + defer file.Close() + + // 解码图片 + img, _, err := image.Decode(file) + // for .webp image + if err != nil { + img, err = webp.Decode(file) + } + if err != nil { + c.String(http.StatusInternalServerError, "Error decoding image") + return + } + + var newImg image.Image + if height == 0 || with == 0 { + // 固定宽度,高度自适应 + newImg = resize.Resize(uint(with), uint(height), img, resize.Lanczos3) + } else { + // 生成缩略图 + newImg = resize.Thumbnail(uint(with), uint(height), img, resize.Lanczos3) + } + var buffer bytes.Buffer + err = jpeg.Encode(&buffer, newImg, &jpeg.Options{Quality: quality}) + if err != nil { + logger.Error(err) + c.String(http.StatusInternalServerError, err.Error()) + return + } + + // 设置图片缓存有效期为一年 (365天) + c.Header("Cache-Control", "max-age=31536000, public") + // 直接输出图像数据流 + c.Data(http.StatusOK, "image/jpeg", buffer.Bytes()) + c.Abort() // 中断请求 } c.Next() diff --git a/api/handler/upload_handler.go b/api/handler/upload_handler.go index 9d2c8706..fd7f437d 100644 --- a/api/handler/upload_handler.go +++ b/api/handler/upload_handler.go @@ -17,19 +17,21 @@ import ( "geekai/utils/resp" "github.com/gin-gonic/gin" "gorm.io/gorm" + "io" + "net/http" "time" ) -type UploadHandler struct { +type NetHandler struct { BaseHandler uploaderManager *oss.UploaderManager } -func NewUploadHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManager) *UploadHandler { - return &UploadHandler{BaseHandler: BaseHandler{App: app, DB: db}, uploaderManager: manager} +func NewNetHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManager) *NetHandler { + return &NetHandler{BaseHandler: BaseHandler{App: app, DB: db}, uploaderManager: manager} } -func (h *UploadHandler) Upload(c *gin.Context) { +func (h *NetHandler) Upload(c *gin.Context) { file, err := h.uploaderManager.GetUploadHandler().PutFile(c, "file") if err != nil { resp.ERROR(c, err.Error()) @@ -60,7 +62,7 @@ func (h *UploadHandler) Upload(c *gin.Context) { resp.SUCCESS(c, file) } -func (h *UploadHandler) List(c *gin.Context) { +func (h *NetHandler) List(c *gin.Context) { var data struct { Urls []string `json:"urls,omitempty"` } @@ -95,7 +97,7 @@ func (h *UploadHandler) List(c *gin.Context) { } // Remove remove files -func (h *UploadHandler) Remove(c *gin.Context) { +func (h *NetHandler) Remove(c *gin.Context) { userId := h.GetLoginUserId(c) id := h.GetInt(c, "id", 0) var file model.File @@ -119,3 +121,28 @@ func (h *UploadHandler) Remove(c *gin.Context) { _ = h.uploaderManager.GetUploadHandler().Delete(objectKey) resp.SUCCESS(c) } + +func (h *NetHandler) Download(c *gin.Context) { + fileUrl := c.Query("url") + // 使用http工具下载文件 + if fileUrl == "" { + resp.ERROR(c, types.InvalidArgs) + return + } + // 使用http.Get下载文件 + r, err := http.Get(fileUrl) + if err != nil { + resp.ERROR(c, err.Error()) + return + } + defer r.Body.Close() + + if r.StatusCode != http.StatusOK { + resp.ERROR(c, "error status:"+r.Status) + return + } + + // 将下载的文件内容写入响应 + c.Status(http.StatusOK) + _, _ = io.Copy(c.Writer, r.Body) +} diff --git a/api/main.go b/api/main.go index 58a428be..2cf9a407 100644 --- a/api/main.go +++ b/api/main.go @@ -128,7 +128,7 @@ func main() { fx.Provide(handler.NewChatRoleHandler), fx.Provide(handler.NewUserHandler), fx.Provide(chatimpl.NewChatHandler), - fx.Provide(handler.NewUploadHandler), + fx.Provide(handler.NewNetHandler), fx.Provide(handler.NewSmsHandler), fx.Provide(handler.NewRedeemHandler), fx.Provide(handler.NewCaptchaHandler), @@ -249,10 +249,11 @@ func main() { group.POST("tokens", h.Tokens) group.GET("stop", h.StopGenerate) }), - fx.Invoke(func(s *core.AppServer, h *handler.UploadHandler) { + fx.Invoke(func(s *core.AppServer, h *handler.NetHandler) { s.Engine.POST("/api/upload", h.Upload) s.Engine.POST("/api/upload/list", h.List) s.Engine.GET("/api/upload/remove", h.Remove) + s.Engine.GET("/api/download", h.Download) }), fx.Invoke(func(s *core.AppServer, h *handler.SmsHandler) { group := s.Engine.Group("/api/sms/") diff --git a/web/public/images/loading.gif b/web/public/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..77eb7b88e38e761d60f99516be3f2530552db07d GIT binary patch literal 16618 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 { + axios({ + method: 'GET', + url: url, + responseType: 'blob' // 将响应类型设置为 `blob` + }).then(response => { + resolve(response) + }).catch(err => { + reject(err) + }) + }) +} \ No newline at end of file diff --git a/web/src/views/Luma.vue b/web/src/views/Luma.vue index 94c6cbd7..8f3d8e8e 100644 --- a/web/src/views/Luma.vue +++ b/web/src/views/Luma.vue @@ -2,15 +2,24 @@
-
+
- +
- + + + +