diff --git a/api/config.sample.toml b/api/config.sample.toml index bfaf4256..bd9e1fb3 100644 --- a/api/config.sample.toml +++ b/api/config.sample.toml @@ -71,6 +71,14 @@ TikaHost = "http://tika:9998" AccessToken = "xxl-job-api-token" # 执行器 API 通信 token RegistryKey = "chatgpt-plus" # 任务注册 key + [SmtpConfig] # 注意,阿里云服务器禁用了25号端口,请使用 465 端口,并开启 TLS 连接 + UseTls = false + Host = "smtp.163.com" + Port = 25 + AppName = "极客学长" + From = "test@163.com" # 发件邮箱人地址 + Password = "" #邮箱 stmp 服务授权码 + [AlipayConfig] Enabled = false # 启用支付宝支付通道 SandBox = false # 是否启用沙盒模式 @@ -80,31 +88,12 @@ TikaHost = "http://tika:9998" PublicKey = "certs/alipay/appPublicCert.crt" # 应用公钥证书 AlipayPublicKey = "certs/alipay/alipayPublicCert.crt" # 支付宝公钥证书 RootCert = "certs/alipay/alipayRootCert.crt" # 支付宝根证书 - NotifyURL = "https://ai.r9it.com/api/payment/alipay/notify" # 支付异步回调地址 [HuPiPayConfig] Enabled = false - Name = "wechat" AppId = "" AppSecret = "" ApiURL = "https://api.xunhupay.com" - NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify" - -[SmtpConfig] # 注意,阿里云服务器禁用了25号端口,请使用 465 端口,并开启 TLS 连接 - UseTls = false - Host = "smtp.163.com" - Port = 25 - AppName = "极客学长" - From = "test@163.com" # 发件邮箱人地址 - Password = "" #邮箱 stmp 服务授权码 - -[JPayConfig] # PayJs 支付配置 - Enabled = false - Name = "wechat" # 请不要改动 - AppId = "" # 商户 ID - PrivateKey = "" # 秘钥 - ApiURL = "https://payjs.cn" - NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的 # 微信商户支付 [WechatPayConfig] @@ -114,6 +103,11 @@ TikaHost = "http://tika:9998" SerialNo = "" # API 证书序列号 PrivateKey = "certs/alipay/privateKey.txt" # API 证书私钥文件路径,跟支付宝一样,把私钥文件拷贝到对应的路径,证书路径要映射到容器内 ApiV3Key = "" # APIV3 私钥,这个是你自己在微信支付平台设置的 - NotifyURL = "https://ai.r9it.com/api/payment/wechat/notify" # 支付成功异步回调地址,域名改成自己的 - ReturnURL = "" # 支付成功同步回调地址 +# 易支付 +[GeekPayConfig] + Enabled = true + AppId = "" # 商户ID + PrivateKey = "" # 商户私钥 + ApiURL = "https://pay.geekai.cn" + Methods = ["alipay", "wxpay", "qqpay", "jdpay", "douyin", "paypal"] # 支持的支付方式 diff --git a/api/core/types/config.go b/api/core/types/config.go index 046d0657..a396f9a1 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -58,6 +58,7 @@ type AlipayConfig struct { AlipayPublicKey string // 支付宝公钥文件路径 RootCert string // Root 秘钥路径 NotifyURL string // 异步通知地址 + ReturnURL string // 同步通知地址 } type WechatPayConfig struct { @@ -76,6 +77,7 @@ type HuPiPayConfig struct { //虎皮椒第四方支付配置 AppSecret string // app 密钥 ApiURL string // 支付网关 NotifyURL string // 异步通知地址 + ReturnURL string // 同步通知地址 } // GeekPayConfig GEEK支付配置 @@ -85,6 +87,7 @@ type GeekPayConfig struct { PrivateKey string // 私钥 ApiURL string // API 网关 NotifyURL string // 异步通知地址 + ReturnURL string // 同步通知地址 Methods []string // 支付方式 } diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index 72718fa4..21923da0 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -73,14 +73,21 @@ func NewPaymentHandler( } func (h *PaymentHandler) Pay(c *gin.Context) { - payWay := c.Query("pay_way") - payType := c.Query("pay_type") - productId := c.Query("product_id") - device := c.Query("device") - userId := c.Query("user_id") + var data struct { + PayWay string `json:"pay_way"` + PayType string `json:"pay_type"` + ProductId int `json:"product_id"` + UserId int `json:"user_id"` + Device string `json:"device"` + Host string `json:"host"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } var product model.Product - err := h.DB.Where("id", productId).First(&product).Error + err := h.DB.Where("id", data.ProductId).First(&product).Error if err != nil { resp.ERROR(c, "Product not found") return @@ -92,36 +99,73 @@ func (h *PaymentHandler) Pay(c *gin.Context) { return } var user model.User - err = h.DB.Where("id", userId).First(&user).Error + err = h.DB.Where("id", data.UserId).First(&user).Error if err != nil { resp.NotAuth(c) return } amount, _ := decimal.NewFromFloat(product.Price).Sub(decimal.NewFromFloat(product.Discount)).Float64() - var payURL string - if payWay == "alipay" { // 支付宝 - returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.AlipayConfig.NotifyURL)) + var payURL, returnURL, notifyURL string + switch data.PayWay { + case "alipay": + if h.App.Config.AlipayConfig.NotifyURL != "" { // 用于本地调试支付 + notifyURL = h.App.Config.AlipayConfig.NotifyURL + } else { + notifyURL = fmt.Sprintf("%s/api/payment/notify/alipay", data.Host) + } + if h.App.Config.AlipayConfig.ReturnURL != "" { // 用于本地调试支付 + returnURL = h.App.Config.AlipayConfig.ReturnURL + } else { + returnURL = fmt.Sprintf("%s/payReturn", data.Host) + } money := fmt.Sprintf("%.2f", amount) payURL, err = h.alipayService.PayPC(payment.AlipayParams{ OutTradeNo: orderNo, Subject: product.Name, TotalFee: money, ReturnURL: returnURL, - NotifyURL: h.App.Config.AlipayConfig.NotifyURL, + NotifyURL: notifyURL, }) if err != nil { resp.ERROR(c, "error with generate pay url: "+err.Error()) return } - } else if payWay == "hupi" { // 虎皮椒支付 - returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.HuPiPayConfig.NotifyURL)) + break + case "wechat": + if h.App.Config.WechatPayConfig.NotifyURL != "" { + notifyURL = h.App.Config.WechatPayConfig.NotifyURL + } else { + notifyURL = fmt.Sprintf("%s/api/payment/notify/wechat", data.Host) + } + payURL, err = h.wechatPayService.PayUrlNative(payment.WechatPayParams{ + OutTradeNo: orderNo, + TotalFee: int(amount * 100), + Subject: product.Name, + NotifyURL: notifyURL, + }) + if err != nil { + resp.ERROR(c, err.Error()) + return + } + break + case "hupi": + if h.App.Config.HuPiPayConfig.NotifyURL != "" { + notifyURL = h.App.Config.HuPiPayConfig.NotifyURL + } else { + notifyURL = fmt.Sprintf("%s/api/payment/notify/hupi", data.Host) + } + if h.App.Config.HuPiPayConfig.ReturnURL != "" { + returnURL = h.App.Config.HuPiPayConfig.ReturnURL + } else { + returnURL = fmt.Sprintf("%s/payReturn", data.Host) + } r, err := h.huPiPayService.Pay(payment.HuPiPayParams{ Version: "1.1", TradeOrderId: orderNo, TotalFee: fmt.Sprintf("%f", amount), Title: product.Name, - NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL, + NotifyURL: notifyURL, ReturnURL: returnURL, WapName: "GeekAI助手", }) @@ -129,23 +173,21 @@ func (h *PaymentHandler) Pay(c *gin.Context) { resp.ERROR(c, err.Error()) return } - payURL = r.URL - } else if payWay == "wechat" { - payURL, err = h.wechatPayService.PayUrlNative(payment.WechatPayParams{ - OutTradeNo: orderNo, - TotalFee: int(amount * 100), - Subject: product.Name, - NotifyURL: h.App.Config.WechatPayConfig.NotifyURL, - }) - if err != nil { - resp.ERROR(c, err.Error()) - return + break + case "geek": + if h.App.Config.GeekPayConfig.NotifyURL != "" { + notifyURL = h.App.Config.GeekPayConfig.NotifyURL + } else { + notifyURL = fmt.Sprintf("%s/api/payment/notify/geek", data.Host) } - } else if payWay == "geek" { - returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.GeekPayConfig.NotifyURL)) - if device == "wechat" { - returnURL = fmt.Sprintf("%s/mobile/profile", utils.GetBaseURL(h.App.Config.GeekPayConfig.NotifyURL)) + if h.App.Config.GeekPayConfig.ReturnURL != "" { + data.Host = utils.GetBaseURL(h.App.Config.GeekPayConfig.ReturnURL) + } + if data.Device == "wechat" { // 微信客户端打开,调回手机端用户中心页面 + returnURL = fmt.Sprintf("%s/mobile/profile", data.Host) + } else { + returnURL = fmt.Sprintf("%s/payReturn", data.Host) } params := payment.GeekPayParams{ OutTradeNo: orderNo, @@ -153,10 +195,10 @@ func (h *PaymentHandler) Pay(c *gin.Context) { Name: product.Name, Money: fmt.Sprintf("%f", amount), ClientIP: c.ClientIP(), - Device: device, - Type: payType, + Device: data.Device, + Type: data.PayType, ReturnURL: returnURL, - NotifyURL: h.App.Config.GeekPayConfig.NotifyURL, + NotifyURL: notifyURL, } res, err := h.geekPayService.Pay(params) @@ -165,6 +207,9 @@ func (h *PaymentHandler) Pay(c *gin.Context) { return } payURL = res.PayURL + default: + resp.ERROR(c, "不支持的支付渠道") + return } // 创建订单 @@ -183,8 +228,8 @@ func (h *PaymentHandler) Pay(c *gin.Context) { Subject: product.Name, Amount: amount, Status: types.OrderNotPaid, - PayWay: payWay, - PayType: payType, + PayWay: data.PayWay, + PayType: data.PayType, Remark: utils.JsonEncode(remark), } err = h.DB.Create(&order).Error diff --git a/api/main.go b/api/main.go index b0b637b4..76692bef 100644 --- a/api/main.go +++ b/api/main.go @@ -372,7 +372,7 @@ func main() { }), fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) { group := s.Engine.Group("/api/payment/") - group.GET("doPay", h.Pay) + group.POST("doPay", h.Pay) group.GET("payWays", h.GetPayWays) group.POST("notify/alipay", h.AlipayNotify) group.GET("notify/geek", h.GeekPayNotify) diff --git a/web/.env.development b/web/.env.development index 97c67f7e..772674f1 100644 --- a/web/.env.development +++ b/web/.env.development @@ -1,4 +1,4 @@ -VUE_APP_API_HOST=http://localhost:5678 +VUE_APP_API_HOST=http://www.geekai.me:6004 VUE_APP_WS_HOST=ws://localhost:5678 VUE_APP_USER=18888888888 VUE_APP_PASS=12345678 diff --git a/web/src/views/Member.vue b/web/src/views/Member.vue index de06254d..2e01fa97 100644 --- a/web/src/views/Member.vue +++ b/web/src/views/Member.vue @@ -122,7 +122,7 @@