mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	payment for mobile page is ready
This commit is contained in:
		@@ -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"] # 支持的支付方式
 | 
			
		||||
 
 | 
			
		||||
@@ -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 // 支付方式
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue"
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {checkSession, getSystemInfo} from "@/store/cache";
 | 
			
		||||
import UserProfile from "@/components/UserProfile.vue";
 | 
			
		||||
import PasswordDialog from "@/components/PasswordDialog.vue";
 | 
			
		||||
@@ -200,11 +200,16 @@ const pay = (product, payWay) => {
 | 
			
		||||
  }
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  loadingText.value = "正在生成支付订单..."
 | 
			
		||||
  httpGet(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
 | 
			
		||||
  let host = process.env.VUE_APP_API_HOST
 | 
			
		||||
  if (host === '') {
 | 
			
		||||
    host = `${location.protocol}://${location.host}`;
 | 
			
		||||
  }
 | 
			
		||||
  httpPost(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
 | 
			
		||||
    product_id: product.id,
 | 
			
		||||
    pay_way: payWay.pay_way,
 | 
			
		||||
    pay_type: payWay.pay_type,
 | 
			
		||||
    user_id: user.value.id,
 | 
			
		||||
    host: host,
 | 
			
		||||
    device: "jump"
 | 
			
		||||
  }).then(res => {
 | 
			
		||||
    showDialog.value = true
 | 
			
		||||
 
 | 
			
		||||
@@ -296,11 +296,16 @@ const pay = (product,payWay) => {
 | 
			
		||||
    message: '正在创建订单',
 | 
			
		||||
    forbidClick: true,
 | 
			
		||||
  });
 | 
			
		||||
  httpGet(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
 | 
			
		||||
  let host = process.env.VUE_APP_API_HOST
 | 
			
		||||
  if (host === '') {
 | 
			
		||||
    host = `${location.protocol}://${location.host}`;
 | 
			
		||||
  }
 | 
			
		||||
  httpPost(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
 | 
			
		||||
    product_id: product.id,
 | 
			
		||||
    pay_way: payWay.pay_way,
 | 
			
		||||
    pay_type: payWay.pay_type,
 | 
			
		||||
    user_id: userId.value,
 | 
			
		||||
    host: host,
 | 
			
		||||
    device: "wechat"
 | 
			
		||||
  }).then(res => {
 | 
			
		||||
    location.href = res.data
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user