From d1965deff1d0509db3b51d7f8a9477ef7da77973 Mon Sep 17 00:00:00 2001 From: RockYang Date: Fri, 12 Jul 2024 14:39:14 +0800 Subject: [PATCH] tidy apis --- api/core/app_server.go | 24 +- api/core/types/chat.go | 3 +- api/core/types/task.go | 8 +- api/core/types/web.go | 4 +- api/handler/chatimpl/chat_handler.go | 49 +- api/handler/chatimpl/chat_item_handler.go | 6 +- api/handler/dalle_handler.go | 33 +- api/handler/mj_handler.go | 65 +-- api/handler/order_handler.go | 48 +- api/handler/payment_handler.go | 57 +- api/handler/sd_handler.go | 40 +- api/handler/sms_handler.go | 18 +- api/handler/upload_handler.go | 2 +- api/handler/user_handler.go | 8 +- api/main.go | 18 +- api/utils/resp/response.go | 18 +- database/update-v4.1.0.sql | 4 +- web/src/components/UserOrder.vue | 6 +- web/src/utils/http.js | 8 +- web/src/views/ChatPlus.vue | 7 +- web/src/views/Dalle.vue | 8 +- web/src/views/ImageMj.vue | 8 +- web/src/views/ImageSd.vue | 10 +- web/src/views/Login.vue | 4 +- web/src/views/Member.vue | 2 +- web/src/views/mobile/ImageMj.vue | 637 ---------------------- web/src/views/mobile/ImageSd.vue | 523 ------------------ web/src/views/mobile/ImgWall.vue | 133 ----- web/src/views/mobile/Profile.vue | 2 +- web/src/views/mobile/pages/ImageDall.vue | 8 +- web/src/views/mobile/pages/ImageMj.vue | 8 +- web/src/views/mobile/pages/ImageSd.vue | 8 +- 32 files changed, 203 insertions(+), 1574 deletions(-) delete mode 100644 web/src/views/mobile/ImageMj.vue delete mode 100644 web/src/views/mobile/ImageSd.vue delete mode 100644 web/src/views/mobile/ImgWall.vue diff --git a/api/core/app_server.go b/api/core/app_server.go index dd99a755..12a17567 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -32,31 +32,19 @@ import ( ) type AppServer struct { - Debug bool - Config *types.AppConfig - Engine *gin.Engine - ChatContexts *types.LMap[string, []types.Message] // 聊天上下文 Map [chatId] => []Message - + Debug bool + Config *types.AppConfig + Engine *gin.Engine SysConfig *types.SystemConfig // system config cache - - // 保存 Websocket 会话 UserId, 每个 UserId 只能连接一次 - // 防止第三方直接连接 socket 调用 OpenAI API - ChatSession *types.LMap[string, *types.ChatSession] //map[sessionId]UserId - ChatClients *types.LMap[string, *types.WsClient] // map[sessionId]Websocket 连接集合 - ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function } func NewServer(appConfig *types.AppConfig) *AppServer { gin.SetMode(gin.ReleaseMode) gin.DefaultWriter = io.Discard return &AppServer{ - Debug: false, - Config: appConfig, - Engine: gin.Default(), - ChatContexts: types.NewLMap[string, []types.Message](), - ChatSession: types.NewLMap[string, *types.ChatSession](), - ChatClients: types.NewLMap[string, *types.WsClient](), - ReqCancelFunc: types.NewLMap[string, context.CancelFunc](), + Debug: false, + Config: appConfig, + Engine: gin.Default(), } } diff --git a/api/core/types/chat.go b/api/core/types/chat.go index 3827b860..cdf418b6 100644 --- a/api/core/types/chat.go +++ b/api/core/types/chat.go @@ -53,9 +53,8 @@ type Delta struct { // ChatSession 聊天会话对象 type ChatSession struct { SessionId string `json:"session_id"` + UserId uint `json:"user_id"` ClientIP string `json:"client_ip"` // 客户端 IP - Username string `json:"username"` // 当前登录的 username - UserId uint `json:"user_id"` // 当前登录的 user ID ChatId string `json:"chat_id"` // 客户端聊天会话 ID, 多会话模式专用字段 Model ChatModel `json:"model"` // GPT 模型 } diff --git a/api/core/types/task.go b/api/core/types/task.go index 6224a383..129a83b4 100644 --- a/api/core/types/task.go +++ b/api/core/types/task.go @@ -53,10 +53,10 @@ type SdTaskParams struct { NegPrompt string `json:"neg_prompt"` // 反向提示词 Steps int `json:"steps"` // 迭代步数,默认20 Sampler string `json:"sampler"` // 采样器 - Scheduler string `json:"scheduler"` - FaceFix bool `json:"face_fix"` // 面部修复 - CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7 - Seed int64 `json:"seed"` // 随机数种子 + Scheduler string `json:"scheduler"` // 采样调度 + FaceFix bool `json:"face_fix"` // 面部修复 + CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7 + Seed int64 `json:"seed"` // 随机数种子 Height int `json:"height"` Width int `json:"width"` HdFix bool `json:"hd_fix"` // 启用高清修复 diff --git a/api/core/types/web.go b/api/core/types/web.go index aecf8e61..408d9a58 100644 --- a/api/core/types/web.go +++ b/api/core/types/web.go @@ -37,11 +37,9 @@ type BizCode int const ( Success = BizCode(0) Failed = BizCode(1) - NotAuthorized = BizCode(400) // 未授权 - NotPermission = BizCode(403) // 没有权限 + NotAuthorized = BizCode(401) // 未授权 OkMsg = "Success" ErrorMsg = "系统开小差了" InvalidArgs = "非法参数或参数解析失败" - NoData = "No Data" ) diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index 98c2eefe..776aa47c 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -44,6 +44,8 @@ type ChatHandler struct { redis *redis.Client uploadManager *oss.UploaderManager licenseService *service.LicenseService + ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function + ChatContexts *types.LMap[string, []types.Message] // 聊天上下文 Map [chatId] => []Message } func NewChatHandler(app *core.AppServer, db *gorm.DB, redis *redis.Client, manager *oss.UploaderManager, licenseService *service.LicenseService) *ChatHandler { @@ -52,6 +54,8 @@ func NewChatHandler(app *core.AppServer, db *gorm.DB, redis *redis.Client, manag redis: redis, uploadManager: manager, licenseService: licenseService, + ReqCancelFunc: types.NewLMap[string, context.CancelFunc](), + ChatContexts: types.NewLMap[string, []types.Message](), } } @@ -89,21 +93,10 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { return } - session := h.App.ChatSession.Get(sessionId) - if session == nil { - user, err := h.GetLoginUser(c) - if err != nil { - logger.Info("用户未登录") - c.Abort() - return - } - session = &types.ChatSession{ - SessionId: sessionId, - ClientIP: c.ClientIP(), - Username: user.Username, - UserId: user.Id, - } - h.App.ChatSession.Put(sessionId, session) + session := &types.ChatSession{ + SessionId: sessionId, + ClientIP: c.ClientIP(), + UserId: h.GetLoginUserId(c), } // use old chat data override the chat model and role ID @@ -125,22 +118,18 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { Temperature: chatModel.Temperature, KeyId: chatModel.KeyId, Platform: chatModel.Platform} - logger.Infof("New websocket connected, IP: %s, Username: %s", c.ClientIP(), session.Username) + logger.Infof("New websocket connected, IP: %s", c.ClientIP()) - // 保存会话连接 - h.App.ChatClients.Put(sessionId, client) go func() { for { _, msg, err := client.Receive() if err != nil { logger.Debugf("close connection: %s", client.Conn.RemoteAddr()) client.Close() - h.App.ChatClients.Delete(sessionId) - h.App.ChatSession.Delete(sessionId) - cancelFunc := h.App.ReqCancelFunc.Get(sessionId) + cancelFunc := h.ReqCancelFunc.Get(sessionId) if cancelFunc != nil { cancelFunc() - h.App.ReqCancelFunc.Delete(sessionId) + h.ReqCancelFunc.Delete(sessionId) } return } @@ -160,7 +149,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { logger.Info("Receive a message: ", message.Content) ctx, cancel := context.WithCancel(context.Background()) - h.App.ReqCancelFunc.Put(sessionId, cancel) + h.ReqCancelFunc.Put(sessionId, cancel) // 回复消息 err = h.sendMessage(ctx, session, chatRole, utils.InterfaceToString(message.Content), client) if err != nil { @@ -274,8 +263,8 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio chatCtx := make([]types.Message, 0) messages := make([]types.Message, 0) if h.App.SysConfig.EnableContext { - if h.App.ChatContexts.Has(session.ChatId) { - messages = h.App.ChatContexts.Get(session.ChatId) + if h.ChatContexts.Has(session.ChatId) { + messages = h.ChatContexts.Get(session.ChatId) } else { _ = utils.JsonDecode(role.Context, &messages) if h.App.SysConfig.ContextDeep > 0 { @@ -468,9 +457,9 @@ func getTotalTokens(req types.ApiRequest) int { // StopGenerate 停止生成 func (h *ChatHandler) StopGenerate(c *gin.Context) { sessionId := c.Query("session_id") - if h.App.ReqCancelFunc.Has(sessionId) { - h.App.ReqCancelFunc.Get(sessionId)() - h.App.ReqCancelFunc.Delete(sessionId) + if h.ReqCancelFunc.Has(sessionId) { + h.ReqCancelFunc.Get(sessionId)() + h.ReqCancelFunc.Delete(sessionId) } resp.SUCCESS(c, types.OkMsg) } @@ -628,7 +617,7 @@ func (h *ChatHandler) saveChatHistory( if h.App.SysConfig.EnableContext { chatCtx = append(chatCtx, useMsg) // 提问消息 chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) + h.ChatContexts.Put(session.ChatId, chatCtx) } // 追加聊天记录 @@ -686,7 +675,7 @@ func (h *ChatHandler) saveChatHistory( res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) if res.Error != nil { chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId + chatItem.UserId = userVo.Id chatItem.RoleId = role.Id chatItem.ModelId = session.Model.Id if utf8.RuneCountInString(prompt) > 30 { diff --git a/api/handler/chatimpl/chat_item_handler.go b/api/handler/chatimpl/chat_item_handler.go index 3e04bf6e..bce39249 100644 --- a/api/handler/chatimpl/chat_item_handler.go +++ b/api/handler/chatimpl/chat_item_handler.go @@ -96,7 +96,7 @@ func (h *ChatHandler) Clear(c *gin.Context) { for _, chat := range chats { chatIds = append(chatIds, chat.ChatId) // 清空会话上下文 - h.App.ChatContexts.Delete(chat.ChatId) + h.ChatContexts.Delete(chat.ChatId) } err = h.DB.Transaction(func(tx *gorm.DB) error { res := h.DB.Where("user_id =?", user.Id).Delete(&model.ChatItem{}) @@ -108,8 +108,6 @@ func (h *ChatHandler) Clear(c *gin.Context) { if res.Error != nil { return res.Error } - - // TODO: 是否要删除 MidJourney 绘画记录和图片文件? return nil }) @@ -175,7 +173,7 @@ func (h *ChatHandler) Remove(c *gin.Context) { // TODO: 是否要删除 MidJourney 绘画记录和图片文件? // 清空会话上下文 - h.App.ChatContexts.Delete(chatId) + h.ChatContexts.Delete(chatId) resp.SUCCESS(c, types.OkMsg) } diff --git a/api/handler/dalle_handler.go b/api/handler/dalle_handler.go index 07cd032c..89226638 100644 --- a/api/handler/dalle_handler.go +++ b/api/handler/dalle_handler.go @@ -158,13 +158,13 @@ func (h *DallJobHandler) ImgWall(c *gin.Context) { // JobList 获取 SD 任务列表 func (h *DallJobHandler) JobList(c *gin.Context) { - status := h.GetBool(c, "status") + finish := h.GetBool(c, "finish") userId := h.GetLoginUserId(c) page := h.GetInt(c, "page", 0) pageSize := h.GetInt(c, "page_size", 0) publish := h.GetBool(c, "publish") - err, jobs := h.getData(status, userId, page, pageSize, publish) + err, jobs := h.getData(finish, userId, page, pageSize, publish) if err != nil { resp.ERROR(c, err.Error()) return @@ -214,25 +214,23 @@ func (h *DallJobHandler) getData(finish bool, userId uint, page int, pageSize in // Remove remove task image func (h *DallJobHandler) Remove(c *gin.Context) { - var data struct { - Id uint `json:"id"` - UserId uint `json:"user_id"` - ImgURL string `json:"img_url"` - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + var job model.DallJob + if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil { + resp.ERROR(c, "记录不存在") return } // remove job recode - res := h.DB.Delete(&model.DallJob{Id: data.Id}) + res := h.DB.Delete(&model.DallJob{Id: job.Id}) if res.Error != nil { resp.ERROR(c, res.Error.Error()) return } // remove image - err := h.uploader.GetUploadHandler().Delete(data.ImgURL) + err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { logger.Error("remove image failed: ", err) } @@ -242,16 +240,11 @@ func (h *DallJobHandler) Remove(c *gin.Context) { // Publish 发布/取消发布图片到画廊显示 func (h *DallJobHandler) Publish(c *gin.Context) { - var data struct { - Id uint `json:"id"` - Action bool `json:"action"` // 发布动作,true => 发布,false => 取消分享 - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) - return - } + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享 - res := h.DB.Model(&model.DallJob{Id: data.Id}).UpdateColumn("publish", true) + res := h.DB.Model(&model.DallJob{Id: uint(id), UserId: uint(userId)}).UpdateColumn("publish", action) if res.Error != nil { logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index 7f6f6b7d..56340af1 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -92,19 +92,18 @@ func (h *MidJourneyHandler) Client(c *gin.Context) { // Image 创建一个绘画任务 func (h *MidJourneyHandler) Image(c *gin.Context) { var data struct { - SessionId string `json:"session_id"` TaskType string `json:"task_type"` Prompt string `json:"prompt"` NegPrompt string `json:"neg_prompt"` Rate string `json:"rate"` - Model string `json:"model"` - Chaos int `json:"chaos"` - Raw bool `json:"raw"` - Seed int64 `json:"seed"` - Stylize int `json:"stylize"` + Model string `json:"model"` // 模型 + Chaos int `json:"chaos"` // 创意度取值范围: 0-100 + Raw bool `json:"raw"` // 是否开启原始模型 + Seed int64 `json:"seed"` // 随机数 + Stylize int `json:"stylize"` // 风格化 ImgArr []string `json:"img_arr"` - Tile bool `json:"tile"` - Quality float32 `json:"quality"` + Tile bool `json:"tile"` // 重复平铺 + Quality float32 `json:"quality"` // 画质 Iw float32 `json:"iw"` CRef string `json:"cref"` //生成角色一致的图像 SRef string `json:"sref"` //生成风格一致的图像 @@ -243,17 +242,12 @@ type reqVo struct { ChannelId string `json:"channel_id"` MessageId string `json:"message_id"` MessageHash string `json:"message_hash"` - SessionId string `json:"session_id"` - Prompt string `json:"prompt"` - ChatId string `json:"chat_id"` - RoleId int `json:"role_id"` - Icon string `json:"icon"` } // Upscale send upscale command to MidJourney Bot func (h *MidJourneyHandler) Upscale(c *gin.Context) { var data reqVo - if err := c.ShouldBindJSON(&data); err != nil || data.SessionId == "" { + if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) return } @@ -271,7 +265,6 @@ func (h *MidJourneyHandler) Upscale(c *gin.Context) { UserId: userId, TaskId: taskId, Progress: 0, - Prompt: data.Prompt, Power: h.App.SysConfig.MjActionPower, CreatedAt: time.Now(), } @@ -283,7 +276,6 @@ func (h *MidJourneyHandler) Upscale(c *gin.Context) { h.pool.PushTask(types.MjTask{ Id: job.Id, Type: types.TaskUpscale, - Prompt: data.Prompt, UserId: userId, ChannelId: data.ChannelId, Index: data.Index, @@ -318,7 +310,7 @@ func (h *MidJourneyHandler) Upscale(c *gin.Context) { // Variation send variation command to MidJourney Bot func (h *MidJourneyHandler) Variation(c *gin.Context) { var data reqVo - if err := c.ShouldBindJSON(&data); err != nil || data.SessionId == "" { + if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) return } @@ -337,7 +329,6 @@ func (h *MidJourneyHandler) Variation(c *gin.Context) { UserId: userId, TaskId: taskId, Progress: 0, - Prompt: data.Prompt, Power: h.App.SysConfig.MjActionPower, CreatedAt: time.Now(), } @@ -349,7 +340,6 @@ func (h *MidJourneyHandler) Variation(c *gin.Context) { h.pool.PushTask(types.MjTask{ Id: job.Id, Type: types.TaskVariation, - Prompt: data.Prompt, UserId: userId, Index: data.Index, ChannelId: data.ChannelId, @@ -397,13 +387,13 @@ func (h *MidJourneyHandler) ImgWall(c *gin.Context) { // JobList 获取 MJ 任务列表 func (h *MidJourneyHandler) JobList(c *gin.Context) { - status := h.GetBool(c, "status") + finish := h.GetBool(c, "finish") userId := h.GetLoginUserId(c) page := h.GetInt(c, "page", 0) pageSize := h.GetInt(c, "page_size", 0) publish := h.GetBool(c, "publish") - err, jobs := h.getData(status, userId, page, pageSize, publish) + err, jobs := h.getData(finish, userId, page, pageSize, publish) if err != nil { resp.ERROR(c, err.Error()) return @@ -459,30 +449,27 @@ func (h *MidJourneyHandler) getData(finish bool, userId uint, page int, pageSize // Remove remove task image func (h *MidJourneyHandler) Remove(c *gin.Context) { - var data struct { - Id uint `json:"id"` - UserId uint `json:"user_id"` - ImgURL string `json:"img_url"` - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + var job model.MidJourneyJob + if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil { + resp.ERROR(c, "记录不存在") return } - // remove job recode - res := h.DB.Delete(&model.MidJourneyJob{Id: data.Id}) + res := h.DB.Delete(&job) if res.Error != nil { resp.ERROR(c, res.Error.Error()) return } // remove image - err := h.uploader.GetUploadHandler().Delete(data.ImgURL) + err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { logger.Error("remove image failed: ", err) } - client := h.pool.Clients.Get(data.UserId) + client := h.pool.Clients.Get(uint(job.UserId)) if client != nil { _ = client.Send([]byte("Task Updated")) } @@ -492,16 +479,10 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) { // Publish 发布图片到画廊显示 func (h *MidJourneyHandler) Publish(c *gin.Context) { - var data struct { - Id uint `json:"id"` - Action bool `json:"action"` // 发布动作,true => 发布,false => 取消分享 - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) - return - } - - res := h.DB.Model(&model.MidJourneyJob{Id: data.Id}).UpdateColumn("publish", data.Action) + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享 + res := h.DB.Model(&model.MidJourneyJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action) if res.Error != nil { logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") diff --git a/api/handler/order_handler.go b/api/handler/order_handler.go index a56daa82..55348e1b 100644 --- a/api/handler/order_handler.go +++ b/api/handler/order_handler.go @@ -14,6 +14,7 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" + "time" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -27,23 +28,18 @@ func NewOrderHandler(app *core.AppServer, db *gorm.DB) *OrderHandler { return &OrderHandler{BaseHandler: BaseHandler{App: app, DB: db}} } +// List 订单列表 func (h *OrderHandler) List(c *gin.Context) { - var data struct { - Page int `json:"page"` - PageSize int `json:"page_size"` - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) - return - } + page := h.GetInt(c, "page", 1) + pageSize := h.GetInt(c, "page_size", 20) userId := h.GetLoginUserId(c) session := h.DB.Session(&gorm.Session{}).Where("user_id = ? AND status = ?", userId, types.OrderPaidSuccess) var total int64 session.Model(&model.Order{}).Count(&total) var items []model.Order var list = make([]vo.Order, 0) - offset := (data.Page - 1) * data.PageSize - res := session.Order("id DESC").Offset(offset).Limit(data.PageSize).Find(&items) + offset := (page - 1) * pageSize + res := session.Order("id DESC").Offset(offset).Limit(pageSize).Find(&items) if res.Error == nil { for _, item := range items { var order vo.Order @@ -58,5 +54,35 @@ func (h *OrderHandler) List(c *gin.Context) { } } } - resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, list)) + resp.SUCCESS(c, vo.NewPage(total, page, pageSize, list)) +} + +// Query 查询订单状态 +func (h *OrderHandler) Query(c *gin.Context) { + orderNo := h.GetTrim(c, "order_no") + var order model.Order + res := h.DB.Where("order_no = ?", orderNo).First(&order) + if res.Error != nil { + resp.ERROR(c, "Order not found") + return + } + + if order.Status == types.OrderPaidSuccess { + resp.SUCCESS(c, gin.H{"status": order.Status}) + return + } + + counter := 0 + for { + time.Sleep(time.Second) + var item model.Order + h.DB.Where("order_no = ?", orderNo).First(&item) + if counter >= 15 || item.Status == types.OrderPaidSuccess || item.Status != order.Status { + order.Status = item.Status + break + } + counter++ + } + + resp.SUCCESS(c, gin.H{"status": order.Status}) } diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index c69f0703..5d807f79 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -111,7 +111,7 @@ func (h *PaymentHandler) DoPay(c *gin.Context) { // fix: 这里先检查一下订单状态,如果已经支付了,就直接返回 if order.Status == types.OrderPaidSuccess { - resp.ERROR(c, "This order had been paid, please do not pay twice") + resp.ERROR(c, "订单已支付成功,无需重复支付!") return } @@ -148,49 +148,11 @@ func (h *PaymentHandler) DoPay(c *gin.Context) { resp.ERROR(c, "Invalid operations") } -// OrderQuery 查询订单状态 -func (h *PaymentHandler) OrderQuery(c *gin.Context) { - var data struct { - OrderNo string `json:"order_no"` - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) - return - } - - var order model.Order - res := h.DB.Where("order_no = ?", data.OrderNo).First(&order) - if res.Error != nil { - resp.ERROR(c, "Order not found") - return - } - - if order.Status == types.OrderPaidSuccess { - resp.SUCCESS(c, gin.H{"status": order.Status}) - return - } - - counter := 0 - for { - time.Sleep(time.Second) - var item model.Order - h.DB.Where("order_no = ?", data.OrderNo).First(&item) - if counter >= 15 || item.Status == types.OrderPaidSuccess || item.Status != order.Status { - order.Status = item.Status - break - } - counter++ - } - - resp.SUCCESS(c, gin.H{"status": order.Status}) -} - // PayQrcode 生成支付 URL 二维码 func (h *PaymentHandler) PayQrcode(c *gin.Context) { var data struct { PayWay string `json:"pay_way"` // 支付方式 ProductId uint `json:"product_id"` - UserId int `json:"user_id"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -209,10 +171,9 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) { resp.ERROR(c, "error with generate trade no: "+err.Error()) return } - var user model.User - res = h.DB.First(&user, data.UserId) - if res.Error != nil { - resp.ERROR(c, "Invalid user ID") + user, err := h.GetLoginUser(c) + if err != nil { + resp.NotAuth(c) return } @@ -333,7 +294,6 @@ func (h *PaymentHandler) Mobile(c *gin.Context) { var data struct { PayWay string `json:"pay_way"` // 支付方式 ProductId uint `json:"product_id"` - UserId int `json:"user_id"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -352,10 +312,9 @@ func (h *PaymentHandler) Mobile(c *gin.Context) { resp.ERROR(c, "error with generate trade no: "+err.Error()) return } - var user model.User - res = h.DB.First(&user, data.UserId) - if res.Error != nil { - resp.ERROR(c, "Invalid user ID") + user, err := h.GetLoginUser(c) + if err != nil { + resp.NotAuth(c) return } @@ -449,7 +408,7 @@ func (h *PaymentHandler) Mobile(c *gin.Context) { return } - resp.SUCCESS(c, payURL) + resp.SUCCESS(c, gin.H{"url": payURL, "order_no": orderNo}) } // 异步通知回调公共逻辑 diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index 5ed3c009..c99d2f9b 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -99,10 +99,7 @@ func (h *SdJobHandler) Image(c *gin.Context) { return } - var data struct { - SessionId string `json:"session_id"` - types.SdTaskParams - } + var data types.SdTaskParams if err := c.ShouldBindJSON(&data); err != nil || data.Prompt == "" { resp.ERROR(c, types.InvalidArgs) return @@ -215,13 +212,13 @@ func (h *SdJobHandler) ImgWall(c *gin.Context) { // JobList 获取 SD 任务列表 func (h *SdJobHandler) JobList(c *gin.Context) { - status := h.GetBool(c, "status") + finish := h.GetBool(c, "finish") userId := h.GetLoginUserId(c) page := h.GetInt(c, "page", 0) pageSize := h.GetInt(c, "page_size", 0) publish := h.GetBool(c, "publish") - err, jobs := h.getData(status, userId, page, pageSize, publish) + err, jobs := h.getData(finish, userId, page, pageSize, publish) if err != nil { resp.ERROR(c, err.Error()) return @@ -280,30 +277,28 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int, // Remove remove task image func (h *SdJobHandler) Remove(c *gin.Context) { - var data struct { - Id uint `json:"id"` - UserId uint `json:"user_id"` - ImgURL string `json:"img_url"` - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + var job model.SdJob + if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil { + resp.ERROR(c, "记录不存在") return } // remove job recode - res := h.DB.Delete(&model.SdJob{Id: data.Id}) + res := h.DB.Delete(&model.SdJob{Id: job.Id}) if res.Error != nil { resp.ERROR(c, res.Error.Error()) return } // remove image - err := h.uploader.GetUploadHandler().Delete(data.ImgURL) + err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { logger.Error("remove image failed: ", err) } - client := h.pool.Clients.Get(data.UserId) + client := h.pool.Clients.Get(uint(job.UserId)) if client != nil { _ = client.Send([]byte(sd.Finished)) } @@ -313,16 +308,11 @@ func (h *SdJobHandler) Remove(c *gin.Context) { // Publish 发布/取消发布图片到画廊显示 func (h *SdJobHandler) Publish(c *gin.Context) { - var data struct { - Id uint `json:"id"` - Action bool `json:"action"` // 发布动作,true => 发布,false => 取消分享 - } - if err := c.ShouldBindJSON(&data); err != nil { - resp.ERROR(c, types.InvalidArgs) - return - } + id := h.GetInt(c, "id", 0) + userId := h.GetInt(c, "user_id", 0) + action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享 - res := h.DB.Model(&model.SdJob{Id: data.Id}).UpdateColumn("publish", true) + res := h.DB.Model(&model.SdJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action) if res.Error != nil { logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") diff --git a/api/handler/sms_handler.go b/api/handler/sms_handler.go index 38a61da6..680f73e1 100644 --- a/api/handler/sms_handler.go +++ b/api/handler/sms_handler.go @@ -49,14 +49,20 @@ func (h *SmsHandler) SendCode(c *gin.Context) { var data struct { Receiver string `json:"receiver"` // 接收者 Key string `json:"key"` - Dots string `json:"dots"` + Dots string `json:"dots,omitempty"` + X int `json:"x,omitempty"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) return } - - if !h.captcha.Check(data) { + var check bool + if data.X != 0 { + check = h.captcha.SlideCheck(data) + } else { + check = h.captcha.Check(data) + } + if !check { resp.ERROR(c, "验证码错误,请先完人机验证") return } @@ -89,5 +95,9 @@ func (h *SmsHandler) SendCode(c *gin.Context) { return } - resp.SUCCESS(c) + if h.App.Debug { + resp.SUCCESS(c, code) + } else { + resp.SUCCESS(c) + } } diff --git a/api/handler/upload_handler.go b/api/handler/upload_handler.go index d47444b0..f144e133 100644 --- a/api/handler/upload_handler.go +++ b/api/handler/upload_handler.go @@ -62,7 +62,7 @@ func (h *UploadHandler) Upload(c *gin.Context) { func (h *UploadHandler) List(c *gin.Context) { var data struct { - Urls []string `json:"urls"` + Urls []string `json:"urls,omitempty"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) diff --git a/api/handler/user_handler.go b/api/handler/user_handler.go index c765a100..6c6bb68b 100644 --- a/api/handler/user_handler.go +++ b/api/handler/user_handler.go @@ -185,7 +185,7 @@ func (h *UserHandler) Register(c *gin.Context) { resp.ERROR(c, "error with save token: "+err.Error()) return } - resp.SUCCESS(c, tokenString) + resp.SUCCESS(c, gin.H{"token": tokenString, "user_id": user.Id, "username": user.Username}) } // Login 用户登录 @@ -244,7 +244,7 @@ func (h *UserHandler) Login(c *gin.Context) { resp.ERROR(c, "error with save token: "+err.Error()) return } - resp.SUCCESS(c, tokenString) + resp.SUCCESS(c, gin.H{"token": tokenString, "user_id": user.Id, "username": user.Username}) } // Logout 注 销 @@ -256,8 +256,8 @@ func (h *UserHandler) Logout(c *gin.Context) { resp.SUCCESS(c) } -// CLoginRequest 第三方登录请求二维码 -func (h *UserHandler) CLoginRequest(c *gin.Context) { +// Clogin 第三方登录请求二维码 +func (h *UserHandler) Clogin(c *gin.Context) { returnURL := h.GetTrim(c, "return_url") var res types.BizVo apiURL := fmt.Sprintf("%s/api/clogin/request", h.App.Config.ApiConfig.ApiURL) diff --git a/api/main.go b/api/main.go index d95358f9..ff036e3f 100644 --- a/api/main.go +++ b/api/main.go @@ -240,7 +240,7 @@ func main() { group.POST("password", h.UpdatePass) group.POST("bind/username", h.BindUsername) group.POST("resetPass", h.ResetPass) - group.GET("clogin/request", h.CLoginRequest) + group.GET("clogin", h.Clogin) group.GET("clogin/callback", h.CLoginCallback) }), fx.Invoke(func(s *core.AppServer, h *chatimpl.ChatHandler) { @@ -283,8 +283,8 @@ func main() { group.POST("variation", h.Variation) group.GET("jobs", h.JobList) group.GET("imgWall", h.ImgWall) - group.POST("remove", h.Remove) - group.POST("publish", h.Publish) + group.GET("remove", h.Remove) + group.GET("publish", h.Publish) }), fx.Invoke(func(s *core.AppServer, h *handler.SdJobHandler) { group := s.Engine.Group("/api/sd") @@ -292,8 +292,8 @@ func main() { group.POST("image", h.Image) group.GET("jobs", h.JobList) group.GET("imgWall", h.ImgWall) - group.POST("remove", h.Remove) - group.POST("publish", h.Publish) + group.GET("remove", h.Remove) + group.GET("publish", h.Publish) }), fx.Invoke(func(s *core.AppServer, h *handler.ConfigHandler) { group := s.Engine.Group("/api/config/") @@ -370,7 +370,6 @@ func main() { group := s.Engine.Group("/api/payment/") group.GET("doPay", h.DoPay) group.GET("payWays", h.GetPayWays) - group.POST("query", h.OrderQuery) group.POST("qrcode", h.PayQrcode) group.POST("mobile", h.Mobile) group.POST("alipay/notify", h.AlipayNotify) @@ -393,7 +392,8 @@ func main() { }), fx.Invoke(func(s *core.AppServer, h *handler.OrderHandler) { group := s.Engine.Group("/api/order/") - group.POST("list", h.List) + group.GET("list", h.List) + group.GET("query", h.Query) }), fx.Invoke(func(s *core.AppServer, h *handler.ProductHandler) { group := s.Engine.Group("/api/product/") @@ -472,8 +472,8 @@ func main() { group.POST("image", h.Image) group.GET("jobs", h.JobList) group.GET("imgWall", h.ImgWall) - group.POST("remove", h.Remove) - group.POST("publish", h.Publish) + group.GET("remove", h.Remove) + group.GET("publish", h.Publish) }), fx.Invoke(func(s *core.AppServer, db *gorm.DB) { go func() { diff --git a/api/utils/resp/response.go b/api/utils/resp/response.go index 3d211246..cc20b2bf 100644 --- a/api/utils/resp/response.go +++ b/api/utils/resp/response.go @@ -24,28 +24,20 @@ func SUCCESS(c *gin.Context, values ...interface{}) { func ERROR(c *gin.Context, messages ...string) { if messages != nil { - c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: messages[0]}) + c.JSON(http.StatusBadRequest, types.BizVo{Code: types.Failed, Message: messages[0]}) } else { - c.JSON(http.StatusOK, types.BizVo{Code: types.Failed}) + c.JSON(http.StatusBadRequest, types.BizVo{Code: types.Failed}) } } func HACKER(c *gin.Context) { - c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Hacker attempt!!!"}) + c.JSON(http.StatusBadRequest, types.BizVo{Code: types.Failed, Message: "Hacker attempt!!!"}) } func NotAuth(c *gin.Context, messages ...string) { if messages != nil { - c.JSON(http.StatusOK, types.BizVo{Code: types.NotAuthorized, Message: messages[0]}) + c.JSON(http.StatusUnauthorized, types.BizVo{Code: types.NotAuthorized, Message: messages[0]}) } else { - c.JSON(http.StatusOK, types.BizVo{Code: types.NotAuthorized, Message: "Not Authorized"}) - } -} - -func NotPermission(c *gin.Context, messages ...string) { - if messages != nil { - c.JSON(http.StatusOK, types.BizVo{Code: types.NotPermission, Message: messages[0]}) - } else { - c.JSON(http.StatusOK, types.BizVo{Code: types.NotPermission, Message: "Not Permission"}) + c.JSON(http.StatusUnauthorized, types.BizVo{Code: types.NotAuthorized, Message: "Not Authorized"}) } } diff --git a/database/update-v4.1.0.sql b/database/update-v4.1.0.sql index 37d36e92..3f55b35a 100644 --- a/database/update-v4.1.0.sql +++ b/database/update-v4.1.0.sql @@ -1,6 +1,6 @@ ALTER TABLE `chatgpt_chat_models` CHANGE `power` `power` SMALLINT NOT NULL COMMENT '消耗算力点数'; ALTER TABLE `chatgpt_users` ADD `openid` VARCHAR(100) NULL COMMENT '第三方登录账号ID' AFTER `last_login_ip`; -ALTER TABLE `chatgpt_users` ADD UNIQUE(`openid`); ALTER TABLE `chatgpt_users` ADD `platform` VARCHAR(30) NULL COMMENT '登录平台' AFTER `openid`; ALTER TABLE `chatgpt_users` CHANGE `avatar` `avatar` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头像'; -ALTER TABLE `chatgpt_chat_history` CHANGE `icon` `icon` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色图标'; \ No newline at end of file +ALTER TABLE `chatgpt_chat_history` CHANGE `icon` `icon` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色图标'; +ALTER TABLE `chatgpt_orders` CHANGE `status` `status` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付成功)'; \ No newline at end of file diff --git a/web/src/components/UserOrder.vue b/web/src/components/UserOrder.vue index 0fdd9bd1..dd8a6c59 100644 --- a/web/src/components/UserOrder.vue +++ b/web/src/components/UserOrder.vue @@ -46,8 +46,8 @@ - - \ No newline at end of file diff --git a/web/src/views/mobile/ImageSd.vue b/web/src/views/mobile/ImageSd.vue deleted file mode 100644 index b310a0a1..00000000 --- a/web/src/views/mobile/ImageSd.vue +++ /dev/null @@ -1,523 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/views/mobile/ImgWall.vue b/web/src/views/mobile/ImgWall.vue deleted file mode 100644 index 8d33a9dd..00000000 --- a/web/src/views/mobile/ImgWall.vue +++ /dev/null @@ -1,133 +0,0 @@ - - - - - diff --git a/web/src/views/mobile/Profile.vue b/web/src/views/mobile/Profile.vue index 48f8b722..cc304d3b 100644 --- a/web/src/views/mobile/Profile.vue +++ b/web/src/views/mobile/Profile.vue @@ -302,7 +302,7 @@ const pay = (payWay, item) => { if (isWeChatBrowser() && payWay === 'wechat') { showFailToast("请在系统自带浏览器打开支付页面,或者在 PC 端进行扫码支付") } else { - location.href = res.data + location.href = res.data.url } }).catch(e => { showFailToast("生成支付订单失败:" + e.message) diff --git a/web/src/views/mobile/pages/ImageDall.vue b/web/src/views/mobile/pages/ImageDall.vue index 6c345b17..f6ad4b1f 100644 --- a/web/src/views/mobile/pages/ImageDall.vue +++ b/web/src/views/mobile/pages/ImageDall.vue @@ -317,7 +317,7 @@ const initData = () => { const fetchRunningJobs = () => { // 获取运行中的任务 - httpGet(`/api/dall/jobs?status=0`).then(res => { + httpGet(`/api/dall/jobs?finish=0`).then(res => { const jobs = res.data const _jobs = [] for (let i = 0; i < jobs.length; i++) { @@ -345,7 +345,7 @@ const pageSize = ref(10) // 获取已完成的任务 const fetchFinishJobs = (page) => { loading.value = true - httpGet(`/api/dall/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => { + httpGet(`/api/dall/jobs?finish=1&page=${page}&page_size=${pageSize.value}`).then(res => { if (res.data.length < pageSize.value) { finished.value = true } @@ -410,7 +410,7 @@ const removeImage = (event, item) => { message: '此操作将会删除任务和图片,继续操作码?', }).then(() => { - httpPost("/api/dall/remove", {id: item.id, img_url: item.img_url, user_id: userId.value}).then(() => { + httpGet("/api/dall/remove", {id: item.id, user_id: item.user_id}).then(() => { showSuccessToast("任务删除成功") }).catch(e => { showFailToast("任务删除失败:" + e.message) @@ -427,7 +427,7 @@ const publishImage = (event, item, action) => { if (action === false) { text = "取消发布" } - httpPost("/api/dall/publish", {id: item.id, action: action}).then(() => { + httpGet("/api/dall/publish", {id: item.id, action: action, user_id: item.user_id}).then(() => { showSuccessToast(text + "成功") item.publish = action }).catch(e => { diff --git a/web/src/views/mobile/pages/ImageMj.vue b/web/src/views/mobile/pages/ImageMj.vue index 46b026e2..d807958b 100644 --- a/web/src/views/mobile/pages/ImageMj.vue +++ b/web/src/views/mobile/pages/ImageMj.vue @@ -421,7 +421,7 @@ const connect = () => { // 获取运行中的任务 const fetchRunningJobs = (userId) => { - httpGet(`/api/mj/jobs?status=0&user_id=${userId}`).then(res => { + httpGet(`/api/mj/jobs?finish=0&user_id=${userId}`).then(res => { const jobs = res.data const _jobs = [] for (let i = 0; i < jobs.length; i++) { @@ -453,7 +453,7 @@ const pageSize = ref(10) const fetchFinishJobs = (page) => { loading.value = true // 获取已完成的任务 - httpGet(`/api/mj/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => { + httpGet(`/api/mj/jobs?finish=1&page=${page}&page_size=${pageSize.value}`).then(res => { const jobs = res.data for (let i = 0; i < jobs.length; i++) { if (jobs[i].progress === -1) { @@ -600,7 +600,7 @@ const removeImage = (item) => { message: '此操作将会删除任务和图片,继续操作码?', }).then(() => { - httpPost("/api/mj/remove", {id: item.id, img_url: item.img_url, user_id: userId.value}).then(() => { + httpGet("/api/mj/remove", {id: item.id, user_id: item.user_id}).then(() => { showSuccessToast("任务删除成功") }).catch(e => { showFailToast("任务删除失败:" + e.message) @@ -615,7 +615,7 @@ const publishImage = (item, action) => { if (action === false) { text = "取消发布" } - httpPost("/api/mj/publish", {id: item.id, action: action}).then(() => { + httpGet("/api/mj/publish", {id: item.id, action: action,user_id: item.user_id}).then(() => { showSuccessToast(text + "成功") item.publish = action }).catch(e => { diff --git a/web/src/views/mobile/pages/ImageSd.vue b/web/src/views/mobile/pages/ImageSd.vue index 50a92f5e..44f90d0a 100644 --- a/web/src/views/mobile/pages/ImageSd.vue +++ b/web/src/views/mobile/pages/ImageSd.vue @@ -381,7 +381,7 @@ const initData = () => { const fetchRunningJobs = () => { // 获取运行中的任务 - httpGet(`/api/sd/jobs?status=0`).then(res => { + httpGet(`/api/sd/jobs?finish=0`).then(res => { const jobs = res.data const _jobs = [] for (let i = 0; i < jobs.length; i++) { @@ -409,7 +409,7 @@ const pageSize = ref(10) // 获取已完成的任务 const fetchFinishJobs = (page) => { loading.value = true - httpGet(`/api/sd/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => { + httpGet(`/api/sd/jobs?finish=1&page=${page}&page_size=${pageSize.value}`).then(res => { if (res.data.length < pageSize.value) { finished.value = true } @@ -474,7 +474,7 @@ const removeImage = (event, item) => { message: '此操作将会删除任务和图片,继续操作码?', }).then(() => { - httpPost("/api/sd/remove", {id: item.id, img_url: item.img_url, user_id: userId.value}).then(() => { + httpGet("/api/sd/remove", {id: item.id, user_id: item.user}).then(() => { showSuccessToast("任务删除成功") }).catch(e => { showFailToast("任务删除失败:" + e.message) @@ -491,7 +491,7 @@ const publishImage = (event, item, action) => { if (action === false) { text = "取消发布" } - httpPost("/api/sd/publish", {id: item.id, action: action}).then(() => { + httpGet("/api/sd/publish", {id: item.id, action: action, user_id: item.user}).then(() => { showSuccessToast(text + "成功") item.publish = action }).catch(e => {